diff --git a/src/active/context.cpp b/src/active/context.cpp index d025c61b6149..be578bd26c97 100644 --- a/src/active/context.cpp +++ b/src/active/context.cpp @@ -36,7 +36,7 @@ ActiveContext::ActiveContext(CBLSWorker& bls_worker, ChainstateManager& chainman m_isman{isman}, m_qman{qman}, nodeman{std::make_unique(connman, dmnman, operator_sk)}, - dkgdbgman{std::make_unique()}, + dkgdbgman{std::make_unique(dmnman, qsnapman, chainman)}, qdkgsman{std::make_unique(dmnman, qsnapman, chainman, sporkman, db_params, quorums_watch)}, shareman{std::make_unique(connman, chainman.ActiveChainstate(), sigman, peerman, *nodeman, qman, sporkman)}, diff --git a/src/active/dkgsession.cpp b/src/active/dkgsession.cpp index 15eb449ece7f..9cdcc3981c81 100644 --- a/src/active/dkgsession.cpp +++ b/src/active/dkgsession.cpp @@ -37,14 +37,14 @@ ActiveDKGSession::~ActiveDKGSession() = default; void ActiveDKGSession::Contribute(CDKGPendingMessages& pendingMessages, PeerManager& peerman) { - CDKGLogger logger(*this, __func__, __LINE__); - if (!AreWeMember()) { return; } assert(params.threshold > 1); // we should not get there with single-node-quorums + CDKGLogger logger(*this, __func__, __LINE__); + cxxtimer::Timer t1(true); logger.Batch("generating contributions"); if (!blsWorker.GenerateContributions(params.threshold, memberIds, vvecContribution, m_sk_contributions)) { @@ -304,7 +304,7 @@ void ActiveDKGSession::VerifyAndJustify(CDKGPendingMessages& pendingMessages, Pe CDKGLogger logger(*this, __func__, __LINE__); - std::set justifyFor; + Uint256HashSet justifyFor; for (const auto& m : members) { if (m->bad) { @@ -338,7 +338,7 @@ void ActiveDKGSession::VerifyAndJustify(CDKGPendingMessages& pendingMessages, Pe } void ActiveDKGSession::SendJustification(CDKGPendingMessages& pendingMessages, PeerManager& peerman, - const std::set& forMembers) + const Uint256HashSet& forMembers) { CDKGLogger logger(*this, __func__, __LINE__); diff --git a/src/active/dkgsession.h b/src/active/dkgsession.h index 412d69e7d84b..3350a06c6b2d 100644 --- a/src/active/dkgsession.h +++ b/src/active/dkgsession.h @@ -43,7 +43,7 @@ class ActiveDKGSession final : public llmq::CDKGSession void VerifyAndJustify(CDKGPendingMessages& pendingMessages, PeerManager& peerman) override EXCLUSIVE_LOCKS_REQUIRED(!invCs); void SendJustification(CDKGPendingMessages& pendingMessages, PeerManager& peerman, - const std::set& forMembers) override; + const Uint256HashSet& forMembers) override; // Phase 4: commit void VerifyAndCommit(CDKGPendingMessages& pendingMessages, PeerManager& peerman) override; diff --git a/src/active/dkgsessionhandler.cpp b/src/active/dkgsessionhandler.cpp index c0ed65b75402..eb10b625a83d 100644 --- a/src/active/dkgsessionhandler.cpp +++ b/src/active/dkgsessionhandler.cpp @@ -251,19 +251,19 @@ void ActiveDKGSessionHandler::HandlePhase(QuorumPhase curPhase, QuorumPhase next // returns a set of NodeIds which sent invalid messages template -std::set BatchVerifyMessageSigs(CDKGSession& session, const std::vector>>& messages) +std::unordered_set BatchVerifyMessageSigs(CDKGSession& session, const std::vector>>& messages) { if (messages.empty()) { return {}; } - std::set ret; + std::unordered_set ret; bool revertToSingleVerification = false; CBLSSignature aggSig; std::vector pubKeys; std::vector messageHashes; - std::set messageHashesSet; + Uint256HashSet messageHashesSet; pubKeys.reserve(messages.size()); messageHashes.reserve(messages.size()); bool first = true; diff --git a/src/llmq/core_write.cpp b/src/llmq/core_write.cpp index 89add66af10b..a5846169a78a 100644 --- a/src/llmq/core_write.cpp +++ b/src/llmq/core_write.cpp @@ -77,8 +77,8 @@ RPCResult CDKGDebugSessionStatus::GetJsonHelp(const std::string& key, bool optio }}; } -// CDKGDebugStatus::ToJson() defined in llmq/debug.cpp -RPCResult CDKGDebugStatus::GetJsonHelp(const std::string& key, bool optional, bool inner_optional) +// CDKGDebugManager::ToJson() defined in llmq/debug.cpp +RPCResult CDKGDebugManager::GetJsonHelp(const std::string& key, bool optional, bool inner_optional) { return {RPCResult::Type::OBJ, key, optional, key.empty() ? "" : "The state of the node's DKG sessions", { diff --git a/src/llmq/debug.cpp b/src/llmq/debug.cpp index 5d48d36682d4..5bd4887d22d4 100644 --- a/src/llmq/debug.cpp +++ b/src/llmq/debug.cpp @@ -107,21 +107,32 @@ UniValue CDKGDebugSessionStatus::ToJson(CDeterministicMNManager& dmnman, CQuorum return ret; } -CDKGDebugManager::CDKGDebugManager() = default; +CDKGDebugManager::CDKGDebugManager(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, + const ChainstateManager& chainman) : + m_dmnman{dmnman}, + m_qsnapman{qsnapman}, + m_chainman{chainman} +{ +} CDKGDebugManager::~CDKGDebugManager() = default; -UniValue CDKGDebugStatus::ToJson(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, - const ChainstateManager& chainman, int detailLevel) const +size_t CDKGDebugManager::GetSessionCount() const { - UniValue ret(UniValue::VOBJ); + return WITH_LOCK(cs_lockStatus, return localStatus.sessions.size()); +} + +UniValue CDKGDebugManager::ToJson(int detailLevel) const +{ + LOCK(cs_lockStatus); - ret.pushKV("time", nTime); - ret.pushKV("timeStr", FormatISO8601DateTime(nTime)); + UniValue ret(UniValue::VOBJ); + ret.pushKV("time", localStatus.nTime); + ret.pushKV("timeStr", FormatISO8601DateTime(localStatus.nTime)); // TODO Support array of sessions UniValue sessionsArrJson(UniValue::VARR); - for (const auto& p : sessions) { + for (const auto& p : localStatus.sessions) { const auto& llmq_params_opt = Params().GetLLMQ(p.first.first); if (!llmq_params_opt.has_value()) { continue; @@ -129,7 +140,7 @@ UniValue CDKGDebugStatus::ToJson(CDeterministicMNManager& dmnman, CQuorumSnapsho UniValue s(UniValue::VOBJ); s.pushKV("llmqType", std::string(llmq_params_opt->name)); s.pushKV("quorumIndex", p.first.second); - s.pushKV("status", p.second.ToJson(dmnman, qsnapman, chainman, p.first.second, detailLevel)); + s.pushKV("status", p.second.ToJson(m_dmnman, m_qsnapman, m_chainman, p.first.second, detailLevel)); sessionsArrJson.push_back(s); } @@ -138,12 +149,6 @@ UniValue CDKGDebugStatus::ToJson(CDeterministicMNManager& dmnman, CQuorumSnapsho return ret; } -void CDKGDebugManager::GetLocalDebugStatus(llmq::CDKGDebugStatus& ret) const -{ - LOCK(cs_lockStatus); - ret = localStatus; -} - void CDKGDebugManager::ResetLocalSessionStatus(Consensus::LLMQType llmqType, int quorumIndex) { LOCK(cs_lockStatus); diff --git a/src/llmq/debug.h b/src/llmq/debug.h index f6923abbe9a4..5fef407fa1b1 100644 --- a/src/llmq/debug.h +++ b/src/llmq/debug.h @@ -10,7 +10,7 @@ #include #include -#include +#include class CDataStream; class CDeterministicMNManager; @@ -45,7 +45,7 @@ class CDKGDebugMemberStatus uint8_t statusBitset; }; - std::set complaintsFromMembers; + std::unordered_set complaintsFromMembers; public: CDKGDebugMemberStatus() : statusBitset(0) {} @@ -83,22 +83,18 @@ class CDKGDebugSessionStatus const ChainstateManager& chainman, int quorumIndex, int detailLevel) const; }; -class CDKGDebugStatus -{ -public: +struct CDKGDebugStatus { int64_t nTime{0}; - std::map, CDKGDebugSessionStatus> sessions; - //std::map sessions; - -public: - [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional, bool inner_optional = false); - [[nodiscard]] UniValue ToJson(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, - const ChainstateManager& chainman, int detailLevel) const; }; class CDKGDebugManager { +private: + CDeterministicMNManager& m_dmnman; + CQuorumSnapshotManager& m_qsnapman; + const ChainstateManager& m_chainman; + private: mutable Mutex cs_lockStatus; CDKGDebugStatus localStatus GUARDED_BY(cs_lockStatus); @@ -106,11 +102,9 @@ class CDKGDebugManager public: CDKGDebugManager(const CDKGDebugManager&) = delete; CDKGDebugManager& operator=(const CDKGDebugManager&) = delete; - CDKGDebugManager(); + CDKGDebugManager(CDeterministicMNManager& dmnman, CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman); ~CDKGDebugManager(); - void GetLocalDebugStatus(CDKGDebugStatus& ret) const EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus); - void ResetLocalSessionStatus(Consensus::LLMQType llmqType, int quorumIndex) EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus); void InitLocalSessionStatus(const Consensus::LLMQParams& llmqParams, int quorumIndex, const uint256& quorumHash, int quorumHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus); @@ -121,8 +115,13 @@ class CDKGDebugManager void UpdateLocalMemberStatus(Consensus::LLMQType llmqType, int quorumIndex, size_t memberIdx, std::function&& func) EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus); -}; + size_t GetSessionCount() const + EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus); + [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional, bool inner_optional = false); + [[nodiscard]] UniValue ToJson(int detailLevel) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_lockStatus); +}; } // namespace llmq #endif // BITCOIN_LLMQ_DEBUG_H diff --git a/src/llmq/dkgsession.cpp b/src/llmq/dkgsession.cpp index fba7e8b38d39..d4013645c977 100644 --- a/src/llmq/dkgsession.cpp +++ b/src/llmq/dkgsession.cpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace llmq { CDKGLogger::CDKGLogger(const CDKGSession& _quorumDkg, std::string_view _func, int source_line) : @@ -197,42 +198,15 @@ bool CDKGSession::PreVerifyMessage(const CDKGContribution& qc, bool& retBan) con return true; } -// TODO: remove duplicated code between all ReceiveMessage: CDKGContribution, CDKGComplaint, CDKGJustification, CDKGPrematureCommitment std::optional CDKGSession::ReceiveMessage(const CDKGContribution& qc) { CDKGLogger logger(*this, __func__, __LINE__); - - auto* member = GetMember(qc.proTxHash); - cxxtimer::Timer t1(true); - logger.Batch("received contribution from %s", qc.proTxHash.ToString()); - // relay, no matter if further verification fails - // This ensures the whole quorum sees the bad behavior - - if (member->contributions.size() >= 2) { - // only relay up to 2 contributions, that's enough to let the other members know about his bad behavior - return std::nullopt; - } - - const uint256 hash = ::SerializeHash(qc); - WITH_LOCK(invCs, contributions.emplace(hash, qc)); - member->contributions.emplace(hash); - - CInv inv(MSG_QUORUM_CONTRIB, hash); - - dkgDebugManager.UpdateLocalMemberStatus(params.type, quorumIndex, member->idx, [&](CDKGDebugMemberStatus& status) { - status.statusBits.receivedContribution = true; - return true; - }); - - if (member->contributions.size() > 1) { - // don't do any further processing if we got more than 1 contribution. we already relayed it, - // so others know about his bad behavior - MarkBadMember(member->idx); - logger.Batch("%s did send multiple contributions", member->dmn->proTxHash.ToString()); - return inv; - } + auto state = WITH_LOCK(invCs, return ReceiveMessagePreamble(qc, MsgPhase::Contribution, logger)); + if (!state) return std::nullopt; + auto& [member, hash, inv, should_process] = *state; + if (!should_process) return inv; receivedVvecs[member->idx] = qc.vvec; @@ -240,13 +214,11 @@ std::optional CDKGSession::ReceiveMessage(const CDKGContribution& qc) logger.Batch("received and relayed contribution. received=%d/%d, time=%d", receivedCount, members.size(), t1.count()); - cxxtimer::Timer t2(true); - if (!AreWeMember()) { - // can't further validate return inv; } + cxxtimer::Timer t2(true); dkgManager.WriteVerifiedVvecContribution(params.type, m_quorum_base_block_index, qc.proTxHash, qc.vvec); bool complain = false; @@ -327,33 +299,10 @@ std::optional CDKGSession::ReceiveMessage(const CDKGComplaint& qc) { CDKGLogger logger(*this, __func__, __LINE__); - logger.Batch("received complaint from %s", qc.proTxHash.ToString()); - - auto* member = GetMember(qc.proTxHash); - - if (member->complaints.size() >= 2) { - // only relay up to 2 complaints, that's enough to let the other members know about his bad behavior - return std::nullopt; - } - - const uint256 hash = ::SerializeHash(qc); - WITH_LOCK(invCs, complaints.emplace(hash, qc)); - member->complaints.emplace(hash); - - CInv inv(MSG_QUORUM_COMPLAINT, hash); - - dkgDebugManager.UpdateLocalMemberStatus(params.type, quorumIndex, member->idx, [&](CDKGDebugMemberStatus& status) { - status.statusBits.receivedComplaint = true; - return true; - }); - - if (member->complaints.size() > 1) { - // don't do any further processing if we got more than 1 complaint. we already relayed it, - // so others know about his bad behavior - MarkBadMember(member->idx); - logger.Batch("%s did send multiple complaints", member->dmn->proTxHash.ToString()); - return inv; - } + auto state = WITH_LOCK(invCs, return ReceiveMessagePreamble(qc, MsgPhase::Complaint, logger)); + if (!state) return std::nullopt; + auto& [member, hash, inv, should_process] = *state; + if (!should_process) return inv; int receivedCount = 0; for (const auto i : irange::range(members.size())) { @@ -409,7 +358,7 @@ bool CDKGSession::PreVerifyMessage(const CDKGJustification& qj, bool& retBan) co return false; } - std::set contributionsSet; + std::unordered_set contributionsSet; for (const auto& p : qj.contributions) { if (p.index > members.size()) { logger.Batch("invalid contribution index"); @@ -447,34 +396,10 @@ std::optional CDKGSession::ReceiveMessage(const CDKGJustification& qj) { CDKGLogger logger(*this, __func__, __LINE__); - logger.Batch("received justification from %s", qj.proTxHash.ToString()); - - auto* member = GetMember(qj.proTxHash); - - if (member->justifications.size() >= 2) { - // only relay up to 2 justifications, that's enough to let the other members know about his bad behavior - return std::nullopt; - } - - const uint256 hash = ::SerializeHash(qj); - WITH_LOCK(invCs, justifications.emplace(hash, qj)); - member->justifications.emplace(hash); - - // we always relay, even if further verification fails - CInv inv(MSG_QUORUM_JUSTIFICATION, hash); - - dkgDebugManager.UpdateLocalMemberStatus(params.type, quorumIndex, member->idx, [&](CDKGDebugMemberStatus& status) { - status.statusBits.receivedJustification = true; - return true; - }); - - if (member->justifications.size() > 1) { - // don't do any further processing if we got more than 1 justification. we already relayed it, - // so others know about his bad behavior - logger.Batch("%s did send multiple justifications", member->dmn->proTxHash.ToString()); - MarkBadMember(member->idx); - return inv; - } + auto state = WITH_LOCK(invCs, return ReceiveMessagePreamble(qj, MsgPhase::Justification, logger)); + if (!state) return std::nullopt; + auto& [member, hash, inv, should_process] = *state; + if (!should_process) return inv; if (member->bad) { // we locally determined him to be bad (sent none or more then one contributions) @@ -683,6 +608,76 @@ CDKGMember* CDKGSession::GetMember(const uint256& proTxHash) const return members[it->second].get(); } +template +std::optional CDKGSession::ReceiveMessagePreamble(const MsgType& msg, MsgPhase phase, CDKGLogger& logger) +{ + auto* member = GetMember(msg.proTxHash); + + GetDataMsg inv_type{0}; + std::string msg_name; + + // Select member set, inv type, and name based on phase + auto& member_set = [&]() -> Uint256HashSet& { + switch (phase) { + case MsgPhase::Contribution: + inv_type = MSG_QUORUM_CONTRIB; + msg_name = "contribution"; + return member->contributions; + case MsgPhase::Complaint: + inv_type = MSG_QUORUM_COMPLAINT; + msg_name = "complaint"; + return member->complaints; + case MsgPhase::Justification: + inv_type = MSG_QUORUM_JUSTIFICATION; + msg_name = "justification"; + return member->justifications; + } + assert(false); + }(); + + logger.Batch("received %s from %s", msg_name, msg.proTxHash.ToString()); + + if (member_set.size() >= 2) { + // only relay up to 2 justifications, that's enough to let the other members know about his bad behavior + return std::nullopt; + } + + const uint256 hash = ::SerializeHash(msg); + member_set.emplace(hash); + if constexpr (std::is_same_v) { + contributions.emplace(hash, msg); + } else if constexpr (std::is_same_v) { + complaints.emplace(hash, msg); + } else if constexpr (std::is_same_v) { + justifications.emplace(hash, msg); + } + + dkgDebugManager.UpdateLocalMemberStatus(params.type, quorumIndex, member->idx, [phase](CDKGDebugMemberStatus& status) { + switch (phase) { + case MsgPhase::Contribution: status.statusBits.receivedContribution = true; break; + case MsgPhase::Complaint: status.statusBits.receivedComplaint = true; break; + case MsgPhase::Justification: status.statusBits.receivedJustification = true; break; + } + return true; + }); + + bool should_process{true}; + if (member_set.size() > 1) { + // don't do any further processing if we got more than 1 justification. we already relayed it, + // so others know about his bad behavior + MarkBadMember(member->idx); + logger.Batch("%s did send multiple %ss", member->dmn->proTxHash.ToString(), msg_name); + should_process = false; + } + + // we always relay, even if further verification fails + return ReceiveMessageState{member, hash, CInv{inv_type, hash}, should_process}; +} + +template std::optional CDKGSession::ReceiveMessagePreamble(const CDKGContribution&, MsgPhase, CDKGLogger&); +template std::optional CDKGSession::ReceiveMessagePreamble(const CDKGComplaint&, MsgPhase, CDKGLogger&); +template std::optional CDKGSession::ReceiveMessagePreamble(const CDKGJustification&, MsgPhase, CDKGLogger&); + void CDKGSession::MarkBadMember(size_t idx) { auto* member = members.at(idx).get(); diff --git a/src/llmq/dkgsession.h b/src/llmq/dkgsession.h index 16b2e1416653..c93e9130f929 100644 --- a/src/llmq/dkgsession.h +++ b/src/llmq/dkgsession.h @@ -6,6 +6,7 @@ #define BITCOIN_LLMQ_DKGSESSION_H #include +#include #include #include @@ -21,7 +22,6 @@ #include class CActiveMasternodeManager; -class CInv; class CConnman; class CDeterministicMN; class CMasternodeMetaMan; @@ -215,13 +215,13 @@ class CDKGMember size_t idx; CBLSId id; - std::set contributions; - std::set complaints; - std::set justifications; - std::set prematureCommitments; + Uint256HashSet contributions; + Uint256HashSet complaints; + Uint256HashSet justifications; + Uint256HashSet prematureCommitments; - std::set badMemberVotes; - std::set complaintsFromOthers; + Uint256HashSet badMemberVotes; + Uint256HashSet complaintsFromOthers; bool bad{false}; bool badConnection{false}; @@ -281,6 +281,20 @@ class CDKGSession friend class CDKGSessionManager; friend class CDKGLogger; +private: + enum class MsgPhase : uint8_t { + Contribution, + Complaint, + Justification + }; + + struct ReceiveMessageState { + CDKGMember* member; + uint256 hash; + CInv inv; + bool should_process; + }; + private: CBLSWorker& blsWorker; CBLSWorkerCache cache; @@ -325,7 +339,7 @@ class CDKGSession std::vector pendingContributionVerifications GUARDED_BY(cs_pending); // filled by ReceivePrematureCommitment and used by FinalizeCommitments - std::set validCommitments GUARDED_BY(invCs); + Uint256HashSet validCommitments GUARDED_BY(invCs); public: CDKGSession(CBLSWorker& _blsWorker, CDeterministicMNManager& dmnman, CDKGDebugManager& _dkgDebugManager, @@ -366,7 +380,7 @@ class CDKGSession // Phase 3: justification virtual void VerifyAndJustify(CDKGPendingMessages& pendingMessages, PeerManager& peerman) EXCLUSIVE_LOCKS_REQUIRED(!invCs) {} - virtual void SendJustification(CDKGPendingMessages& pendingMessages, PeerManager& peerman, const std::set& forMembers) {} + virtual void SendJustification(CDKGPendingMessages& pendingMessages, PeerManager& peerman, const Uint256HashSet& forMembers) {} bool PreVerifyMessage(const CDKGJustification& qj, bool& retBan) const; std::optional ReceiveMessage(const CDKGJustification& qj) EXCLUSIVE_LOCKS_REQUIRED(!invCs); @@ -400,12 +414,16 @@ class CDKGSession private: [[nodiscard]] bool ShouldSimulateError(DKGError::type type) const; + + template + [[nodiscard]] std::optional ReceiveMessagePreamble(const MsgType& msg, MsgPhase phase, CDKGLogger& logger) + EXCLUSIVE_LOCKS_REQUIRED(invCs); + void MarkBadMember(size_t idx); }; void SetSimulatedDKGErrorRate(DKGError::type type, double rate); double GetSimulatedErrorRate(DKGError::type type); - } // namespace llmq #endif // BITCOIN_LLMQ_DKGSESSION_H diff --git a/src/llmq/dkgsessionhandler.h b/src/llmq/dkgsessionhandler.h index 19ea22cdd6c7..04fa3781e947 100644 --- a/src/llmq/dkgsessionhandler.h +++ b/src/llmq/dkgsessionhandler.h @@ -67,7 +67,7 @@ class CDKGPendingMessages mutable Mutex cs_messages; std::list pendingMessages GUARDED_BY(cs_messages); std::map messagesPerNode GUARDED_BY(cs_messages); - std::set seenMessages GUARDED_BY(cs_messages); + Uint256HashSet seenMessages GUARDED_BY(cs_messages); public: explicit CDKGPendingMessages(size_t _maxMessagesPerNode, uint32_t _invType) : diff --git a/src/llmq/ehf_signals.h b/src/llmq/ehf_signals.h index cc9893061dca..33600f85475f 100644 --- a/src/llmq/ehf_signals.h +++ b/src/llmq/ehf_signals.h @@ -7,6 +7,7 @@ #include #include +#include #include @@ -32,7 +33,8 @@ class CEHFSignalsHandler : public CRecoveredSigsListener * keep freshly generated IDs for easier filter sigs in HandleNewRecoveredSig */ mutable Mutex cs; - std::set ids GUARDED_BY(cs); + Uint256HashSet ids GUARDED_BY(cs); + public: explicit CEHFSignalsHandler(ChainstateManager& chainman, CMNHFManager& mnhfman, CSigningManager& sigman, CSigSharesManager& shareman, const CQuorumManager& qman); diff --git a/src/llmq/observer/context.cpp b/src/llmq/observer/context.cpp index 7fe664cee825..82312fb66960 100644 --- a/src/llmq/observer/context.cpp +++ b/src/llmq/observer/context.cpp @@ -19,7 +19,7 @@ ObserverContext::ObserverContext(CBLSWorker& bls_worker, CConnman& connman, CDet const CSporkManager& sporkman, const llmq::QvvecSyncModeMap& sync_map, const util::DbWrapperParams& db_params, bool quorums_recovery) : m_qman{qman}, - dkgdbgman{std::make_unique()}, + dkgdbgman{std::make_unique(dmnman, qsnapman, chainman)}, qdkgsman{std::make_unique(dmnman, qsnapman, chainman, sporkman, db_params, /*quorums_watch=*/true)}, qman_handler{std::make_unique(connman, dmnman, qman, qsnapman, chainman, mn_sync, sporkman, diff --git a/src/llmq/observer/quorums.cpp b/src/llmq/observer/quorums.cpp index cd37b14f86d9..4a2f9b68165a 100644 --- a/src/llmq/observer/quorums.cpp +++ b/src/llmq/observer/quorums.cpp @@ -334,7 +334,7 @@ void QuorumObserver::StartCleanupOldQuorumDataThread(gsl::not_null dbKeysToSkip; + Uint256HashSet dbKeysToSkip; if (LOCK(cs_cleanup); cleanupQuorumsCache.empty()) { utils::InitQuorumsCache(cleanupQuorumsCache, m_chainman.GetConsensus(), /*limit_by_connections=*/false); @@ -346,7 +346,7 @@ void QuorumObserver::StartCleanupOldQuorumDataThread(gsl::not_null quorum_keys; + Uint256HashSet quorum_keys; while (pindex_loop != nullptr && pIndex->nHeight - pindex_loop->nHeight < params.max_store_depth()) { uint256 quorum_key; if (cache.get(pindex_loop->GetBlockHash(), quorum_key)) { diff --git a/src/llmq/observer/quorums.h b/src/llmq/observer/quorums.h index 020dc62e7fa5..bb20d8035d8a 100644 --- a/src/llmq/observer/quorums.h +++ b/src/llmq/observer/quorums.h @@ -59,7 +59,7 @@ class QuorumObserverParent gsl::not_null pindexStart, size_t nCountRequested) const = 0; virtual void CleanupExpiredDataRequests() const = 0; - virtual void CleanupOldQuorumData(const std::set& dbKeysToSkip) const = 0; + virtual void CleanupOldQuorumData(const Uint256HashSet& dbKeysToSkip) const = 0; }; class QuorumObserver diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index 51108903cd70..060305c077db 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -26,7 +26,7 @@ uint256 MakeQuorumKey(const CQuorum& q) return hw.GetHash(); } -void DataCleanupHelper(CDBWrapper& db, const std::set& skip_list, bool compact) +void DataCleanupHelper(CDBWrapper& db, const Uint256HashSet& skip_list, bool compact) { const auto prefixes = {DB_QUORUM_QUORUM_VVEC, DB_QUORUM_SK_SHARE}; diff --git a/src/llmq/quorums.h b/src/llmq/quorums.h index 6e3899723c8c..02ca9ed4d121 100644 --- a/src/llmq/quorums.h +++ b/src/llmq/quorums.h @@ -35,7 +35,7 @@ extern const std::string DB_QUORUM_SK_SHARE; extern const std::string DB_QUORUM_QUORUM_VVEC; uint256 MakeQuorumKey(const CQuorum& q); -void DataCleanupHelper(CDBWrapper& db, const std::set& skip_list, bool compact = false); +void DataCleanupHelper(CDBWrapper& db, const Uint256HashSet& skip_list, bool compact = false); /** * Object used as a key to store CQuorumDataRequest diff --git a/src/llmq/quorumsman.cpp b/src/llmq/quorumsman.cpp index ffcb90878fbf..36efc974e840 100644 --- a/src/llmq/quorumsman.cpp +++ b/src/llmq/quorumsman.cpp @@ -82,7 +82,7 @@ CQuorumPtr CQuorumManager::BuildQuorumFromCommitment(const Consensus::LLMQType l quorum->Init(std::make_unique(std::move(qc)), pQuorumBaseBlockIndex, minedBlockHash, members); if (populate_cache && llmq_params_opt->size == 1) { - WITH_LOCK(cs_map_quorums, mapQuorumsCache[llmqType].insert(quorumHash, quorum)); + WITH_LOCK(m_cs_maps, mapQuorumsCache[llmqType].insert(quorumHash, quorum)); return quorum; } @@ -106,7 +106,7 @@ CQuorumPtr CQuorumManager::BuildQuorumFromCommitment(const Consensus::LLMQType l QueueQuorumForWarming(quorum); } - WITH_LOCK(cs_map_quorums, mapQuorumsCache[llmqType].insert(quorumHash, quorum)); + WITH_LOCK(m_cs_maps, mapQuorumsCache[llmqType].insert(quorumHash, quorum)); return quorum; } @@ -230,7 +230,7 @@ std::vector CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp std::vector vecResultQuorums; { - LOCK(cs_scan_quorums); + LOCK(m_cs_maps); if (scanQuorumsCache.empty()) { for (const auto& llmq : Params().GetConsensus().llmqs) { // NOTE: We store it for each block hash in the DKG mining phase here @@ -293,7 +293,7 @@ std::vector CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp const size_t nCountResult{vecResultQuorums.size()}; if (nCountResult > 0) { - LOCK(cs_scan_quorums); + LOCK(m_cs_maps); // Don't cache more than keepOldConnections elements // because signing by old quorums requires the exact quorum hash // to be specified and quorum scanning isn't needed there. @@ -359,7 +359,7 @@ void CQuorumManager::CleanupExpiredDataRequests() const } } -void CQuorumManager::CleanupOldQuorumData(const std::set& dbKeysToSkip) const +void CQuorumManager::CleanupOldQuorumData(const Uint256HashSet& dbKeysToSkip) const { LOCK(cs_db); DataCleanupHelper(*db, dbKeysToSkip); @@ -399,7 +399,7 @@ CQuorumCPtr CQuorumManager::GetQuorum(Consensus::LLMQType llmqType, gsl::not_nul } CQuorumPtr pQuorum; - if (LOCK(cs_map_quorums); mapQuorumsCache[llmqType].get(quorumHash, pQuorum)) { + if (LOCK(m_cs_maps); mapQuorumsCache[llmqType].get(quorumHash, pQuorum)) { return pQuorum; } @@ -530,7 +530,7 @@ MessageProcessingResult CQuorumManager::ProcessMessage(CNode& pfrom, CConnman& c CQuorumPtr pQuorum; { - if (LOCK(cs_map_quorums); !mapQuorumsCache[request.GetLLMQType()].get(request.GetQuorumHash(), pQuorum)) { + if (LOCK(m_cs_maps); !mapQuorumsCache[request.GetLLMQType()].get(request.GetQuorumHash(), pQuorum)) { // Don't bump score because we asked for it LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- %s: Quorum not found, from peer=%d\n", __func__, msg_type, pfrom.GetId()); return {}; diff --git a/src/llmq/quorumsman.h b/src/llmq/quorumsman.h index 98fdaf5f6c65..d4427bfaea6c 100644 --- a/src/llmq/quorumsman.h +++ b/src/llmq/quorumsman.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -83,12 +84,11 @@ class CQuorumManager final : public QuorumObserverParent mutable std::unordered_map mapQuorumDataRequests GUARDED_BY(cs_data_requests); - mutable Mutex cs_map_quorums; - mutable std::map> mapQuorumsCache GUARDED_BY(cs_map_quorums); - - mutable Mutex cs_scan_quorums; // TODO: merge cs_map_quorums, cs_scan_quorums mutexes + mutable Mutex m_cs_maps; + mutable std::map> mapQuorumsCache + GUARDED_BY(m_cs_maps); mutable std::map>> scanQuorumsCache - GUARDED_BY(cs_scan_quorums); + GUARDED_BY(m_cs_maps); // On mainnet, we have around 62 quorums active at any point; let's cache a little more than double that to be safe. // it maps `quorum_hash` to `pindex` @@ -130,7 +130,7 @@ class CQuorumManager final : public QuorumObserverParent [[nodiscard]] MessageProcessingResult ProcessMessage(CNode& pfrom, CConnman& connman, std::string_view msg_type, CDataStream& vRecv) - EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_data_requests, !cs_map_quorums, !m_cache_cs); + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_data_requests, !m_cs_maps, !m_cache_cs); static bool HasQuorum(Consensus::LLMQType llmqType, const CQuorumBlockProcessor& quorum_block_processor, const uint256& quorumHash); @@ -140,14 +140,14 @@ class CQuorumManager final : public QuorumObserverParent // all these methods will lock cs_main for a short period of time CQuorumCPtr GetQuorum(Consensus::LLMQType llmqType, const uint256& quorumHash) const - EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_map_quorums, !m_cache_cs); + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps, !m_cache_cs); std::vector ScanQuorums(Consensus::LLMQType llmqType, size_t nCountRequested) const - EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_map_quorums, !cs_scan_quorums, !m_cache_cs); + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps, !m_cache_cs); // this one is cs_main-free std::vector ScanQuorums(Consensus::LLMQType llmqType, gsl::not_null pindexStart, size_t nCountRequested) const override - EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_map_quorums, !cs_scan_quorums, !m_cache_cs); + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps, !m_cache_cs); bool IsMasternode() const; bool IsWatching() const; @@ -158,7 +158,7 @@ class CQuorumManager final : public QuorumObserverParent Consensus::LLMQType llmqType) const override EXCLUSIVE_LOCKS_REQUIRED(!cs_data_requests); void CleanupExpiredDataRequests() const override EXCLUSIVE_LOCKS_REQUIRED(!cs_data_requests); - void CleanupOldQuorumData(const std::set& dbKeysToSkip) const override EXCLUSIVE_LOCKS_REQUIRED(!cs_db); + void CleanupOldQuorumData(const Uint256HashSet& dbKeysToSkip) const override EXCLUSIVE_LOCKS_REQUIRED(!cs_db); private: // all private methods here are cs_main-free @@ -167,11 +167,11 @@ class CQuorumManager final : public QuorumObserverParent CQuorumPtr BuildQuorumFromCommitment(Consensus::LLMQType llmqType, gsl::not_null pQuorumBaseBlockIndex, bool populate_cache) const - EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_map_quorums, !m_cache_cs); + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps, !m_cache_cs); CQuorumCPtr GetQuorum(Consensus::LLMQType llmqType, gsl::not_null pindex, bool populate_cache = true) const - EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !cs_map_quorums, !m_cache_cs); + EXCLUSIVE_LOCKS_REQUIRED(!cs_db, !m_cs_maps, !m_cache_cs); void QueueQuorumForWarming(CQuorumCPtr pQuorum) const EXCLUSIVE_LOCKS_REQUIRED(!m_cache_cs); void CacheWarmingThreadMain() const EXCLUSIVE_LOCKS_REQUIRED(!m_cache_cs); diff --git a/src/llmq/signing.cpp b/src/llmq/signing.cpp index 0e12e31bf547..31d09511d414 100644 --- a/src/llmq/signing.cpp +++ b/src/llmq/signing.cpp @@ -181,8 +181,7 @@ void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType l if (deleteTimeKey) { CDataStream writeTimeDs(SER_DISK, CLIENT_VERSION); - // TODO remove the size() == sizeof(uint32_t) in a future version (when we stop supporting upgrades from < 0.14.1) - if (db->ReadDataStream(k2, writeTimeDs) && writeTimeDs.size() == sizeof(uint32_t)) { + if (db->ReadDataStream(k2, writeTimeDs)) { uint32_t writeTime; writeTimeDs >> writeTime; auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t) htobe32_internal(writeTime), recSig.getLlmqType(), recSig.getId()); diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index 71720b6a3ba1..24f74988dbfb 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -754,8 +754,9 @@ Uint256HashSet GetQuorumRelayMembers(const Consensus::LLMQParams& llmqParams, co return result; } -std::set CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, gsl::not_null pQuorumBaseBlockIndex, - size_t memberCount, size_t connectionCount) +std::unordered_set CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, + gsl::not_null pQuorumBaseBlockIndex, + size_t memberCount, size_t connectionCount) { static uint256 qwatchConnectionSeed; static std::atomic qwatchConnectionSeedGenerated{false}; @@ -766,7 +767,7 @@ std::set CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, qwatchConnectionSeedGenerated = true; } - std::set result; + std::unordered_set result; uint256 rnd = qwatchConnectionSeed; for ([[maybe_unused]] const auto _ : irange::range(connectionCount)) { rnd = ::SerializeHash(std::make_pair(rnd, std::make_pair(llmqType, pQuorumBaseBlockIndex->GetBlockHash()))); @@ -841,7 +842,7 @@ void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman auto members = GetAllQuorumMembers(llmqParams.type, util_params); auto curTime = GetTime().count(); - std::set probeConnections; + Uint256HashSet probeConnections; for (const auto& dmn : members) { if (dmn->proTxHash == myProTxHash) { continue; diff --git a/src/llmq/utils.h b/src/llmq/utils.h index 5279baf8cf4c..4cf36cc20fac 100644 --- a/src/llmq/utils.h +++ b/src/llmq/utils.h @@ -62,9 +62,9 @@ struct BlsCheck { uint256 DeterministicOutboundConnection(const uint256& proTxHash1, const uint256& proTxHash2); -std::set CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, - gsl::not_null pQuorumBaseBlockIndex, - size_t memberCount, size_t connectionCount); +std::unordered_set CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, + gsl::not_null pQuorumBaseBlockIndex, + size_t memberCount, size_t connectionCount); // includes members which failed DKG std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, const UtilParameters& util_params, diff --git a/src/net.cpp b/src/net.cpp index f62ebb16820d..99c478f3013d 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -4455,7 +4455,7 @@ bool CConnman::IsMasternodeQuorumRelayMember(const uint256& protxHash) return false; } -void CConnman::AddPendingProbeConnections(const std::set &proTxHashes) +void CConnman::AddPendingProbeConnections(const Uint256HashSet& proTxHashes) { LOCK(cs_vPendingMasternodes); masternodePendingProbes.insert(proTxHashes.begin(), proTxHashes.end()); diff --git a/src/net.h b/src/net.h index 1da1093f187b..9e4e15ed2f7a 100644 --- a/src/net.h +++ b/src/net.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -24,18 +25,18 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include + +#include +#include #include -#include #include #include @@ -1465,7 +1466,7 @@ friend class CNode; void RemoveMasternodeQuorumNodes(Consensus::LLMQType llmqType, const uint256& quorumHash); bool IsMasternodeQuorumNode(const CNode* pnode, const CDeterministicMNList& tip_mn_list) const; bool IsMasternodeQuorumRelayMember(const uint256& protxHash); - void AddPendingProbeConnections(const std::set& proTxHashes); + void AddPendingProbeConnections(const Uint256HashSet& proTxHashes); size_t GetNodeCount(ConnectionDirection) const EXCLUSIVE_LOCKS_REQUIRED(!m_nodes_mutex); std::map getNetLocalAddresses() const; @@ -1782,7 +1783,7 @@ friend class CNode; mutable RecursiveMutex cs_vPendingMasternodes; std::map, Uint256HashSet> masternodeQuorumNodes GUARDED_BY(cs_vPendingMasternodes); std::map, Uint256HashSet> masternodeQuorumRelayMembers GUARDED_BY(cs_vPendingMasternodes); - std::set masternodePendingProbes GUARDED_BY(cs_vPendingMasternodes); + Uint256HashSet masternodePendingProbes GUARDED_BY(cs_vPendingMasternodes); mutable Mutex cs_mapSocketToNode; std::unordered_map mapSocketToNode GUARDED_BY(cs_mapSocketToNode); diff --git a/src/rpc/client.cpp b/src/rpc/client.cpp index 636ca29d6163..b8a73c4f87e2 100644 --- a/src/rpc/client.cpp +++ b/src/rpc/client.cpp @@ -255,8 +255,24 @@ static const CRPCConvertParam vRPCConvertParams[] = { "verifyislock", 3, "maxHeight" }, { "submitchainlock", 2, "blockHeight" }, { "mnauth", 0, "nodeId" }, + // Compound RPCs (note: index position is offset by one to account for subcommand) + { "gobject list-prepared", 1, "count" }, + { "gobject prepare", 2, "revision" }, + { "gobject prepare", 3, "time" }, + { "gobject prepare", 7, "outputIndex" }, + { "gobject submit", 2, "revision" }, + { "gobject submit", 3, "time" }, + { "masternode payments", 2, "count" }, + { "protx diff", 1, "baseBlock" }, + { "protx diff", 2, "block" }, + { "protx list", 3, "height" }, + { "protx listdiff", 1, "baseBlock" }, + { "protx listdiff", 2, "block" }, + { "protx register", 2, "collateralIndex" }, { "protx register", 3, "coreP2PAddrs", true }, + { "protx register_legacy", 2, "collateralIndex" }, { "protx register_legacy", 3, "coreP2PAddrs", true }, + { "protx register_evo", 2, "collateralIndex" }, { "protx register_evo", 3, "coreP2PAddrs", true }, { "protx register_evo", 10, "platformP2PAddrs", true }, { "protx register_evo", 11, "platformHTTPSAddrs", true }, @@ -265,15 +281,35 @@ static const CRPCConvertParam vRPCConvertParams[] = { "protx register_fund_evo", 2, "coreP2PAddrs", true }, { "protx register_fund_evo", 9, "platformP2PAddrs", true }, { "protx register_fund_evo", 10, "platformHTTPSAddrs", true }, + { "protx register_prepare", 2, "collateralIndex" }, { "protx register_prepare", 3, "coreP2PAddrs", true }, + { "protx register_prepare_legacy", 2, "collateralIndex" }, { "protx register_prepare_legacy", 3, "coreP2PAddrs", true }, + { "protx register_prepare_evo", 2, "collateralIndex" }, { "protx register_prepare_evo", 3, "coreP2PAddrs", true }, { "protx register_prepare_evo", 10, "platformP2PAddrs", true }, { "protx register_prepare_evo", 11, "platformHTTPSAddrs", true }, + { "protx revoke", 3, "reason" }, { "protx update_service", 2, "coreP2PAddrs", true }, { "protx update_service_evo", 2, "coreP2PAddrs", true }, { "protx update_service_evo", 5, "platformP2PAddrs", true }, { "protx update_service_evo", 6, "platformHTTPSAddrs", true }, + { "quorum dkgsimerror", 2, "rate" }, + { "quorum dkgstatus", 1, "detail_level" }, + { "quorum getdata", 1, "nodeId" }, + { "quorum getdata", 2, "llmqType" }, + { "quorum getdata", 4, "dataMask" }, + { "quorum getrecsig", 1, "llmqType" }, + { "quorum hasrecsig", 1, "llmqType" }, + { "quorum info", 1, "llmqType" }, + { "quorum isconflicting", 1, "llmqType" }, + { "quorum listextended", 1, "height" }, + { "quorum list", 1, "count" }, + { "quorum memberof", 2, "scanQuorumsCount" }, + { "quorum selectquorum", 1, "llmqType" }, + { "quorum sign", 1, "llmqType" }, + { "quorum verify", 1, "llmqType" }, + { "quorum verify", 6, "signHeight" }, }; // clang-format on diff --git a/src/rpc/evo.cpp b/src/rpc/evo.cpp index d5d9c0dc1f1e..e1d6b7f9475c 100644 --- a/src/rpc/evo.cpp +++ b/src/rpc/evo.cpp @@ -713,7 +713,7 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request, paramIdx++; } else { uint256 collateralHash(ParseHashV(request.params[paramIdx], "collateralHash")); - int32_t collateralIndex = ParseInt32V(request.params[paramIdx + 1], "collateralIndex"); + int32_t collateralIndex = request.params[paramIdx + 1].getInt(); if (collateralHash.IsNull() || collateralIndex < 0) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid hash or index: %s-%d", collateralHash.ToString(), collateralIndex)); } @@ -1267,7 +1267,7 @@ static RPCHelpMan protx_revoke() CBLSSecretKey keyOperator = ParseBLSSecretKey(request.params[1].get_str(), "operatorKey"); if (!request.params[2].isNull()) { - int32_t nReason = ParseInt32V(request.params[2], "reason"); + int32_t nReason = request.params[2].getInt(); if (nReason < 0 || nReason > CProUpRevTx::REASON_LAST) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("invalid reason %d, must be between 0 and %d", nReason, CProUpRevTx::REASON_LAST)); } @@ -1452,7 +1452,7 @@ static RPCHelpMan protx_list() bool detailed = !request.params[1].isNull() ? ParseBoolV(request.params[1], "detailed") : false; LOCK2(wallet->cs_wallet, ::cs_main); - int height = !request.params[2].isNull() ? ParseInt32V(request.params[2], "height") : chainman.ActiveChain().Height(); + int height = !request.params[2].isNull() ? request.params[2].getInt() : chainman.ActiveChain().Height(); if (height < 1 || height > chainman.ActiveChain().Height()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid height specified"); } @@ -1485,7 +1485,7 @@ static RPCHelpMan protx_list() #else LOCK(::cs_main); #endif - int height = !request.params[2].isNull() ? ParseInt32V(request.params[2], "height") : chainman.ActiveChain().Height(); + int height = !request.params[2].isNull() ? request.params[2].getInt() : chainman.ActiveChain().Height(); if (height < 1 || height > chainman.ActiveChain().Height()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid height specified"); } diff --git a/src/rpc/governance.cpp b/src/rpc/governance.cpp index 6dd142cbbbd2..13f7cf6f609f 100644 --- a/src/rpc/governance.cpp +++ b/src/rpc/governance.cpp @@ -176,8 +176,8 @@ static RPCHelpMan gobject_prepare() hashParent = ParseHashV(request.params[0], "parent-hash"); } - int nRevision = ParseInt32V(request.params[1], "revision"); - int64_t nTime = ParseInt64V(request.params[2], "time"); + int nRevision = request.params[1].getInt(); + int64_t nTime = request.params[2].getInt(); std::string strDataHex = request.params[3].get_str(); // CREATE A NEW COLLATERAL TRANSACTION FOR THIS SPECIFIC OBJECT @@ -225,7 +225,7 @@ static RPCHelpMan gobject_prepare() outpoint.SetNull(); if (!request.params[5].isNull() && !request.params[6].isNull()) { uint256 collateralHash(ParseHashV(request.params[5], "outputHash")); - int32_t collateralIndex = ParseInt32V(request.params[6], "outputIndex"); + int32_t collateralIndex = request.params[6].getInt(); if (collateralHash.IsNull() || collateralIndex < 0) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("invalid hash or index: %s-%d", collateralHash.ToString(), collateralIndex)); } @@ -278,7 +278,7 @@ static RPCHelpMan gobject_list_prepared() if (!wallet) return UniValue::VNULL; EnsureWalletIsUnlocked(*wallet); - int64_t nCount = request.params.empty() ? 10 : ParseInt64V(request.params[0], "count"); + int64_t nCount = request.params.empty() ? 10 : request.params[0].getInt(); if (nCount < 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count"); } @@ -361,8 +361,8 @@ static RPCHelpMan gobject_submit() // GET THE PARAMETERS FROM USER - int nRevision = ParseInt32V(request.params[1], "revision"); - int64_t nTime = ParseInt64V(request.params[2], "time"); + int nRevision = request.params[1].getInt(); + int64_t nTime = request.params[2].getInt(); std::string strDataHex = request.params[3].get_str(); CGovernanceObject govobj(hashParent, nRevision, nTime, txidFee, strDataHex); diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 6ba736403719..36e367ce6ceb 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -382,7 +382,7 @@ static RPCHelpMan masternode_payments() } } - int64_t nCount = request.params.size() > 1 ? ParseInt64V(request.params[1], "count") : 1; + int64_t nCount = request.params.size() > 1 ? request.params[1].getInt() : 1; // A temporary vector which is used to sort results properly (there is no "reverse" in/for UniValue) std::vector vecPayments; diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index f82ec32def8d..13b747bc2873 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -69,7 +69,7 @@ static RPCHelpMan quorum_list() int count = -1; if (!request.params[0].isNull()) { - count = ParseInt32V(request.params[0], "count"); + count = request.params[0].getInt(); if (count < -1) { throw JSONRPCError(RPC_INVALID_PARAMETER, "count can't be negative"); } @@ -135,7 +135,7 @@ static RPCHelpMan quorum_list_extended() int nHeight = -1; if (!request.params[0].isNull()) { - nHeight = ParseInt32V(request.params[0], "height"); + nHeight = request.params[0].getInt(); if (nHeight < 0 || nHeight > WITH_LOCK(cs_main, return chainman.ActiveChain().Height())) { throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range"); } @@ -274,7 +274,7 @@ static RPCHelpMan quorum_info() const NodeContext& node = EnsureAnyNodeContext(request.context); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); - const Consensus::LLMQType llmqType{static_cast(ParseInt32V(request.params[0], "llmqType"))}; + const Consensus::LLMQType llmqType{static_cast(request.params[0].getInt())}; if (!Params().GetLLMQ(llmqType).has_value()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); } @@ -297,7 +297,7 @@ static RPCHelpMan quorum_info() static RPCResult quorum_dkgstatus_help() { - auto ret = llmq::CDKGDebugStatus::GetJsonHelp(/*key=*/"", /*optional=*/false, /*inner_optional=*/true); + auto ret = llmq::CDKGDebugManager::GetJsonHelp(/*key=*/"", /*optional=*/false, /*inner_optional=*/true); auto mod_inner = ret.m_inner; mod_inner.push_back({RPCResult::Type::ARR, "quorumConnections", "Array of objects containing quorum connection information", { {RPCResult::Type::OBJ, "", "", { @@ -335,7 +335,7 @@ static RPCHelpMan quorum_dkgstatus() { int detailLevel = 0; if (!request.params[0].isNull()) { - detailLevel = ParseInt32V(request.params[0], "detail_level"); + detailLevel = request.params[0].getInt(); if (detailLevel < 0 || detailLevel > 2) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid detail_level"); } @@ -346,18 +346,16 @@ static RPCHelpMan quorum_dkgstatus() UniValue quorumArrConnections(UniValue::VARR); const NodeContext& node = EnsureAnyNodeContext(request.context); - const ChainstateManager& chainman = EnsureChainman(node); - const LLMQContext& llmq_ctx = EnsureLLMQContext(node); if (const auto* debugman = node.active_ctx ? node.active_ctx->dkgdbgman.get() : node.observer_ctx ? node.observer_ctx->dkgdbgman.get() : nullptr; debugman) { - llmq::CDKGDebugStatus status; - debugman->GetLocalDebugStatus(status); - ret = status.ToJson(*CHECK_NONFATAL(node.dmnman), *llmq_ctx.qsnapman, chainman, detailLevel); + ret = debugman->ToJson(detailLevel); } const CConnman& connman = EnsureConnman(node); + const ChainstateManager& chainman = EnsureChainman(node); const CBlockIndex* const pindexTip = WITH_LOCK(cs_main, return chainman.ActiveChain().Tip()); + const LLMQContext& llmq_ctx = EnsureLLMQContext(node); const int tipHeight = pindexTip->nHeight; const uint256 proTxHash = node.active_ctx ? node.active_ctx->nodeman->GetProTxHash() : uint256{}; for (const auto& type : llmq::GetEnabledQuorumTypes(chainman, pindexTip)) { @@ -461,7 +459,7 @@ static RPCHelpMan quorum_memberof() uint256 protxHash(ParseHashV(request.params[0], "proTxHash")); int scanQuorumsCount = -1; if (!request.params[1].isNull()) { - scanQuorumsCount = ParseInt32V(request.params[1], "scanQuorumsCount"); + scanQuorumsCount = request.params[1].getInt(); if (scanQuorumsCount <= 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid scanQuorumsCount parameter"); } @@ -591,7 +589,7 @@ static RPCHelpMan quorum_sign() RPCExamples{""}, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { - const Consensus::LLMQType llmqType{static_cast(ParseInt32V(request.params[0], "llmqType"))}; + const Consensus::LLMQType llmqType{static_cast(request.params[0].getInt())}; JSONRPCRequest new_request{request}; new_request.params.setArray(); @@ -660,7 +658,7 @@ static RPCHelpMan quorum_verify() const ChainstateManager& chainman = EnsureChainman(node); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); - const Consensus::LLMQType llmqType{static_cast(ParseInt32V(request.params[0], "llmqType"))}; + const Consensus::LLMQType llmqType{static_cast(request.params[0].getInt())}; const auto llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { @@ -679,7 +677,7 @@ static RPCHelpMan quorum_verify() if (request.params[4].isNull() || (request.params[4].get_str().empty() && !request.params[5].isNull())) { int signHeight{-1}; if (!request.params[5].isNull()) { - signHeight = ParseInt32V(request.params[5], "signHeight"); + signHeight = request.params[5].getInt(); } return VerifyRecoveredSigLatestQuorums(*llmq_params_opt, chainman.ActiveChain(), *llmq_ctx.qman, signHeight, id, msgHash, sig); } @@ -713,7 +711,7 @@ static RPCHelpMan quorum_hasrecsig() const NodeContext& node = EnsureAnyNodeContext(request.context); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); - const Consensus::LLMQType llmqType{static_cast(ParseInt32V(request.params[0], "llmqType"))}; + const Consensus::LLMQType llmqType{static_cast(request.params[0].getInt())}; if (!Params().GetLLMQ(llmqType).has_value()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); } @@ -742,7 +740,7 @@ static RPCHelpMan quorum_getrecsig() const NodeContext& node = EnsureAnyNodeContext(request.context); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); - const Consensus::LLMQType llmqType{static_cast(ParseInt32V(request.params[0], "llmqType"))}; + const Consensus::LLMQType llmqType{static_cast(request.params[0].getInt())}; if (!Params().GetLLMQ(llmqType).has_value()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); } @@ -778,7 +776,7 @@ static RPCHelpMan quorum_isconflicting() const NodeContext& node = EnsureAnyNodeContext(request.context); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); - const Consensus::LLMQType llmqType{static_cast(ParseInt32V(request.params[0], "llmqType"))}; + const Consensus::LLMQType llmqType{static_cast(request.params[0].getInt())}; if (!Params().GetLLMQ(llmqType).has_value()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); } @@ -815,7 +813,7 @@ static RPCHelpMan quorum_selectquorum() const ChainstateManager& chainman = EnsureChainman(node); const LLMQContext& llmq_ctx = EnsureLLMQContext(node); - const Consensus::LLMQType llmqType{static_cast(ParseInt32V(request.params[0], "llmqType"))}; + const Consensus::LLMQType llmqType{static_cast(request.params[0].getInt())}; const auto llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); @@ -857,7 +855,7 @@ static RPCHelpMan quorum_dkgsimerror() [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { std::string type_str = request.params[0].get_str(); - int32_t rate = ParseInt32V(request.params[1], "rate"); + int32_t rate = request.params[1].getInt(); if (rate < 0 || rate > 100) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid rate. Must be between 0 and 100"); @@ -897,10 +895,10 @@ static RPCHelpMan quorum_getdata() const LLMQContext& llmq_ctx = EnsureLLMQContext(node); CConnman& connman = EnsureConnman(node); - NodeId nodeId = ParseInt64V(request.params[0], "nodeId"); - Consensus::LLMQType llmqType = static_cast(ParseInt32V(request.params[1], "llmqType")); + NodeId nodeId = request.params[0].getInt(); + Consensus::LLMQType llmqType = static_cast(request.params[1].getInt()); uint256 quorumHash(ParseHashV(request.params[2], "quorumHash")); - uint16_t nDataMask = static_cast(ParseInt32V(request.params[3], "dataMask")); + uint16_t nDataMask = static_cast(request.params[3].getInt()); uint256 proTxHash; // Check if request wants ENCRYPTED_CONTRIBUTIONS data @@ -1004,10 +1002,8 @@ static RPCHelpMan quorum_dkginfo() } const auto& dkgdbgman = *(node.active_ctx ? node.active_ctx->dkgdbgman.get() : node.observer_ctx->dkgdbgman.get()); - llmq::CDKGDebugStatus status; - dkgdbgman.GetLocalDebugStatus(status); UniValue ret(UniValue::VOBJ); - ret.pushKV("active_dkgs", status.sessions.size()); + ret.pushKV("active_dkgs", dkgdbgman.GetSessionCount()); const ChainstateManager& chainman = EnsureChainman(node); const int nTipHeight{WITH_LOCK(cs_main, return chainman.ActiveChain().Height())}; diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 9aae2d7e0c96..043f7cf479b4 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -130,15 +130,6 @@ int32_t ParseInt32V(const UniValue& v, const std::string &strName) return num; } -int64_t ParseInt64V(const UniValue& v, const std::string &strName) -{ - const std::string& strNum = v.getValStr(); - int64_t num; - if (!ParseInt64(strNum, &num)) - throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be a 64bit integer (not '"+strNum+"')"); - return num; -} - bool ParseBoolV(const UniValue& v, const std::string &strName) { std::string strBool; diff --git a/src/rpc/util.h b/src/rpc/util.h index fe12b4cbaf4f..a3c6785098d8 100644 --- a/src/rpc/util.h +++ b/src/rpc/util.h @@ -94,8 +94,6 @@ std::vector ParseHexV(const UniValue& v, std::string strName); std::vector ParseHexO(const UniValue& o, std::string strKey); int32_t ParseInt32V(const UniValue& v, const std::string &strName); -int64_t ParseInt64V(const UniValue& v, const std::string &strName); -double ParseDoubleV(const UniValue& v, const std::string &strName); bool ParseBoolV(const UniValue& v, const std::string &strName); /** diff --git a/src/test/rpc_tests.cpp b/src/test/rpc_tests.cpp index 6ebc56e250e1..d7b6b6a305f7 100644 --- a/src/test/rpc_tests.cpp +++ b/src/test/rpc_tests.cpp @@ -612,7 +612,7 @@ BOOST_AUTO_TEST_CASE(rpc_convert_composite_commands) BOOST_CHECK_EQUAL(result[0].get_str(), "register_prepare"); BOOST_CHECK_EQUAL(result[1].get_str(), "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000"); - BOOST_CHECK_EQUAL(result[2].get_str(), "1"); + BOOST_CHECK_EQUAL(result[2].getInt(), 1); BOOST_CHECK(result[3].isArray()); BOOST_CHECK_EQUAL(result[3].size(), 2); BOOST_CHECK_EQUAL(result[3][0].get_str(), "1.1.1.1:19999"); diff --git a/test/functional/feature_llmq_dkgerrors.py b/test/functional/feature_llmq_dkgerrors.py index 187bea3b8bc8..f86c656200cd 100755 --- a/test/functional/feature_llmq_dkgerrors.py +++ b/test/functional/feature_llmq_dkgerrors.py @@ -37,18 +37,18 @@ def run_test(self): mninfos_valid = self.mninfo.copy()[1:] self.log.info("Lets omit the contribution") - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'contribution-omit', '100') + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'contribution-omit', 100) qh = self.mine_quorum(expected_contributions=2, mninfos_valid=mninfos_valid) self.assert_member_valid(qh, self.mninfo[0].proTxHash, False) self.log.info("Lets lie in the contribution but provide a correct justification") - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'contribution-omit', '0') - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'contribution-lie', '100') + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'contribution-omit', 0) + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'contribution-lie', 100) qh = self.mine_quorum(expected_contributions=3, expected_complaints=2, expected_justifications=1, mninfos_valid=mninfos_valid) self.assert_member_valid(qh, self.mninfo[0].proTxHash, True) self.log.info("Lets lie in the contribution and then omit the justification") - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'justify-omit', '100') + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'justify-omit', 100) qh = self.mine_quorum(expected_contributions=3, expected_complaints=2, mninfos_valid=mninfos_valid) self.assert_member_valid(qh, self.mninfo[0].proTxHash, False) @@ -56,27 +56,27 @@ def run_test(self): self.heal_masternodes(33) self.log.info("Lets lie in the contribution and then also lie in the justification") - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'justify-omit', '0') - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'justify-lie', '100') + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'justify-omit', 0) + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'justify-lie', 100) qh = self.mine_quorum(expected_contributions=3, expected_complaints=2, expected_justifications=1, mninfos_valid=mninfos_valid) self.assert_member_valid(qh, self.mninfo[0].proTxHash, False) self.log.info("Lets lie about another MN") - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'contribution-lie', '0') - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'justify-lie', '0') - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'complain-lie', '100') + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'contribution-lie', 0) + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'justify-lie', 0) + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'complain-lie', 100) qh = self.mine_quorum(expected_contributions=3, expected_complaints=1, expected_justifications=2, mninfos_valid=mninfos_valid) self.assert_member_valid(qh, self.mninfo[0].proTxHash, True) self.log.info("Lets omit 1 premature commitments") - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'complain-lie', '0') - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'commit-omit', '100') + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'complain-lie', 0) + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'commit-omit', 100) qh = self.mine_quorum(expected_contributions=3, expected_complaints=0, expected_justifications=0, expected_commitments=2, mninfos_valid=mninfos_valid) self.assert_member_valid(qh, self.mninfo[0].proTxHash, True) self.log.info("Lets lie in 1 premature commitments") - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'commit-omit', '0') - self.mninfo[0].get_node(self).quorum('dkgsimerror', 'commit-lie', '100') + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'commit-omit', 0) + self.mninfo[0].get_node(self).quorum('dkgsimerror', 'commit-lie', 100) qh = self.mine_quorum(expected_contributions=3, expected_complaints=0, expected_justifications=0, expected_commitments=2, mninfos_valid=mninfos_valid) self.assert_member_valid(qh, self.mninfo[0].proTxHash, True)