From 23b140eb206d7f866edf95869bcbcb60705cb7ce Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Mon, 23 Sep 2019 21:36:55 +0300 Subject: [PATCH 01/12] Introduce getbestchainlock rpc and fix llmq-is-cl-conflicts.py (#3094) * Introduce getbestchainlock rpc and fix llmq-is-cl-conflicts.py * Add `known_block` field and move `getbestchainlock` to `blockchain` rpc category * Add CChainLockSig::IsNull() and throw an exception in getbestchainlock if there is no known chainlock yet * drop blockHash initializer --- src/llmq/quorums_chainlocks.cpp | 13 ++++++++++++- src/llmq/quorums_chainlocks.h | 3 +++ src/rpc/blockchain.cpp | 27 +++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/llmq/quorums_chainlocks.cpp b/src/llmq/quorums_chainlocks.cpp index 811a694cdc10..facdadd1d017 100644 --- a/src/llmq/quorums_chainlocks.cpp +++ b/src/llmq/quorums_chainlocks.cpp @@ -23,6 +23,11 @@ static const std::string CLSIG_REQUESTID_PREFIX = "clsig"; std::unique_ptr chainLocksHandler{nullptr}; +bool CChainLockSig::IsNull() const +{ + return nHeight == -1 && blockHash == uint256(); +} + std::string CChainLockSig::ToString() const { return strprintf("CChainLockSig(nHeight=%d, blockHash=%s)", nHeight, blockHash.ToString()); @@ -72,6 +77,12 @@ bool CChainLocksHandler::GetChainLockByHash(const uint256& hash, llmq::CChainLoc return true; } +CChainLockSig CChainLocksHandler::GetBestChainLock() +{ + LOCK(cs); + return bestChainLock; +} + void CChainLocksHandler::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman) { if (!sporkManager.IsSporkActive(SPORK_23_CHAINLOCKS_ENFORCEMENT)) { @@ -101,7 +112,7 @@ void CChainLocksHandler::ProcessNewChainLock(NodeId from, const llmq::CChainLock return; } - if (bestChainLock.nHeight != -1 && clsig.nHeight <= bestChainLock.nHeight) { + if (!bestChainLock.IsNull() && clsig.nHeight <= bestChainLock.nHeight) { // no need to process/relay older CLSIGs return; } diff --git a/src/llmq/quorums_chainlocks.h b/src/llmq/quorums_chainlocks.h index 6289210e2262..40fdc811f126 100644 --- a/src/llmq/quorums_chainlocks.h +++ b/src/llmq/quorums_chainlocks.h @@ -34,6 +34,8 @@ class CChainLockSig READWRITE(obj.blockHash); READWRITE(obj.sig); } + + bool IsNull() const; std::string ToString() const; }; @@ -70,6 +72,7 @@ class CChainLocksHandler : public CRecoveredSigsListener public: bool AlreadyHave(const CInv& inv); bool GetChainLockByHash(const uint256& hash, CChainLockSig& ret); + CChainLockSig GetBestChainLock(); void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); void ProcessNewChainLock(NodeId from, const CChainLockSig& clsig, const uint256& hash); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index 8f855421f5c6..a30471f4e2f6 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -245,6 +245,32 @@ UniValue getbestsaplinganchor(const JSONRPCRequest& request) return pcoinsTip->GetBestAnchor().ToString(); } +UniValue getbestchainlock(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 0) + throw std::runtime_error( + "getbestchainlock\n" + "\nReturns the block hash of the best chainlock. Throws an error if there is no known chainlock yet.\n" + "\nResult:\n" + "{\n" + " \"blockhash\" : \"hash\", (string) The block hash hex encoded\n" + " \"height\" : n, (numeric) The block height or index\n" + " \"known_block\" : true|false (boolean) True if the block is known by our node\n" + "}\n" + "\nExamples:\n" + + HelpExampleCli("getbestchainlock", "") + HelpExampleRpc("getbestchainlock", "")); + UniValue result(UniValue::VOBJ); + llmq::CChainLockSig clsig = llmq::chainLocksHandler->GetBestChainLock(); + if (clsig.IsNull()) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to find any chainlock"); + } + result.pushKV("blockhash", clsig.blockHash.GetHex()); + result.pushKV("height", clsig.nHeight); + LOCK(cs_main); + result.pushKV("known_block", mapBlockIndex.count(clsig.blockHash) > 0); + return result; +} + void RPCNotifyBlockChange(bool fInitialDownload, const CBlockIndex* pindex) { if(pindex) { @@ -1693,6 +1719,7 @@ static const CRPCCommand commands[] = { "blockchain", "getbestsaplinganchor", &getbestsaplinganchor, true, {} }, { "blockchain", "getblock", &getblock, true, {"blockhash","verbose|verbosity"} }, { "blockchain", "getblockchaininfo", &getblockchaininfo, true, {} }, + { "blockchain", "getbestchainlock", &getbestchainlock, true, {} }, { "blockchain", "getblockcount", &getblockcount, true, {} }, { "blockchain", "getblockhash", &getblockhash, true, {"height"} }, { "blockchain", "getblockheader", &getblockheader, false, {"blockhash","verbose"} }, From cf138e0eedaef98b77f49b9bdc66e9d241b0393a Mon Sep 17 00:00:00 2001 From: Pasta Date: Fri, 15 Nov 2024 09:19:00 +0100 Subject: [PATCH 02/12] cherry-pick https://github.com/dashpay/dash/pull/3097 --- src/llmq/quorums_signing_shares.cpp | 1 - src/llmq/quorums_signing_shares.h | 1 - 2 files changed, 2 deletions(-) diff --git a/src/llmq/quorums_signing_shares.cpp b/src/llmq/quorums_signing_shares.cpp index e6b4fefe3d23..1b1f5c1e1e26 100644 --- a/src/llmq/quorums_signing_shares.cpp +++ b/src/llmq/quorums_signing_shares.cpp @@ -156,7 +156,6 @@ bool CSigSharesNodeState::GetSessionInfoByRecvId(uint32_t sessionId, SessionInfo if (!s) { return false; } - retInfo.recvSessionId = sessionId; retInfo.llmqType = s->llmqType; retInfo.quorumHash = s->quorumHash; retInfo.id = s->id; diff --git a/src/llmq/quorums_signing_shares.h b/src/llmq/quorums_signing_shares.h index 25e819ab317b..d6a9d10890a2 100644 --- a/src/llmq/quorums_signing_shares.h +++ b/src/llmq/quorums_signing_shares.h @@ -273,7 +273,6 @@ class CSigSharesNodeState public: // Used to avoid holding locks too long struct SessionInfo { - uint32_t recvSessionId; Consensus::LLMQType llmqType; uint256 quorumHash; uint256 id; From 27fa2af0facd6e35c0955bbad7a9897ebecebd1e Mon Sep 17 00:00:00 2001 From: Pasta Date: Fri, 15 Nov 2024 09:21:02 +0100 Subject: [PATCH 03/12] cherry-pick https://github.com/dashpay/dash/pull/3117 --- src/llmq/quorums_signing.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index 181661482360..f16157dee185 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -752,7 +752,6 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint } if (!quorum->IsValidMember(activeMasternodeManager->GetProTx())) { - // LogPrint(BCLog::LLMQ, "CSigningManager::%s -- we're not a valid member of quorum %s\n", __func__, quorum->quorumHash.ToString()); return false; } From 479b64be70988a18be2105fc012a579a9809b7a5 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Wed, 16 Oct 2019 16:10:06 +0200 Subject: [PATCH 04/12] Avoid propagating InstantSend related old recovered sigs (#3145) * More/better logging for InstantSend * Implement CRecoveredSigsDb::TruncateRecoveredSig * Truncate recovered sigs for ISLOCKs instead of completely removing them This makes AlreadyHave() return true even when the recovered sig is deleted locally. This avoids re-requesting and re-processing of old recovered sigs. * Also truncate recovered sigs for freshly received ISLOCKs * Fix comment --- src/llmq/quorums_signing.cpp | 37 ++++++++++++++++++++++++++++-------- src/llmq/quorums_signing.h | 7 +++++-- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index f16157dee185..560c90387fd1 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -246,7 +246,7 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig) } } -void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteTimeKey) +void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteHashKey, bool deleteTimeKey) { AssertLockHeld(cs); @@ -263,7 +263,9 @@ void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType l auto k4 = std::make_tuple(std::string("rs_s"), signHash); batch.Erase(k1); batch.Erase(k2); - batch.Erase(k3); + if (deleteHashKey) { + batch.Erase(k3); + } batch.Erase(k4); if (deleteTimeKey) { @@ -279,14 +281,27 @@ void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType l hasSigForIdCache.erase(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id)); hasSigForSessionCache.erase(signHash); - hasSigForHashCache.erase(recSig.GetHash()); + if (deleteHashKey) { + hasSigForHashCache.erase(recSig.GetHash()); + } } +// Completely remove any traces of the recovered sig void CRecoveredSigsDb::RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id) { LOCK(cs); CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT); - RemoveRecoveredSig(batch, llmqType, id, true); + RemoveRecoveredSig(batch, llmqType, id, true, true); + db.WriteBatch(batch); +} + +// Remove the recovered sig itself and all keys required to get from id -> recSig +// This will leave the byHash key in-place so that HasRecoveredSigForHash still returns true +void CRecoveredSigsDb::TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id) +{ + LOCK(cs); + CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT); + RemoveRecoveredSig(batch, llmqType, id, false, false); db.WriteBatch(batch); } @@ -326,7 +341,7 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge) { LOCK(cs); for (auto& e : toDelete) { - RemoveRecoveredSig(batch, e.first, e.second, false); + RemoveRecoveredSig(batch, e.first, e.second, true, false); if (batch.SizeEstimate() >= (1 << 24)) { db.WriteBatch(batch); @@ -459,7 +474,8 @@ void CSigningManager::ProcessMessageRecoveredSig(CNode* pfrom, const CRecoveredS return; } - LogPrint(BCLog::LLMQ, "CSigningManager::%s -- signHash=%s, node=%d\n", __func__, llmq::utils::BuildSignHash(recoveredSig).ToString(), pfrom->GetId()); + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__, + llmq::utils::BuildSignHash(recoveredSig).ToString(), recoveredSig.id.ToString(), recoveredSig.msgHash.ToString(), pfrom->GetId()); LOCK(cs); pendingRecoveredSigs[pfrom->GetId()].emplace_back(recoveredSig); @@ -624,6 +640,11 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re LOCK(cs_main); connman.RemoveAskFor(recoveredSig.GetHash(), MSG_QUORUM_RECOVERED_SIG); } + + if (db.HasRecoveredSigForHash(recoveredSig.GetHash())) { + return; + } + std::vector listeners; { LOCK(cs); @@ -670,9 +691,9 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re } } -void CSigningManager::RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id) +void CSigningManager::TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id) { - db.RemoveRecoveredSig(llmqType, id); + db.TruncateRecoveredSig(llmqType, id); } void CSigningManager::Cleanup() diff --git a/src/llmq/quorums_signing.h b/src/llmq/quorums_signing.h index ac458a3b92d5..23529ffcc2df 100644 --- a/src/llmq/quorums_signing.h +++ b/src/llmq/quorums_signing.h @@ -78,6 +78,7 @@ class CRecoveredSigsDb bool GetRecoveredSigById(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret); void WriteRecoveredSig(const CRecoveredSig& recSig); void RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id); + void TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id); void CleanupOldRecoveredSigs(int64_t maxAge); @@ -90,7 +91,7 @@ class CRecoveredSigsDb private: bool ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret); - void RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteTimeKey); + void RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteHashKey, bool deleteTimeKey); }; class CRecoveredSigsListener @@ -136,7 +137,9 @@ class CSigningManager // This is called when a recovered signature can be safely removed from the DB. This is only safe when some other // mechanism prevents possible conflicts. As an example, ChainLocks prevent conflicts in confirmed TXs InstantSend votes - void RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256& id); + // This won't completely remove all traces of the recovered sig but instead leave the hash entry in the DB. This + // allows AlreadyHave to keep returning true. Cleanup will later remove the remains + void TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id); private: void ProcessMessageRecoveredSig(CNode* pfrom, const CRecoveredSig& recoveredSig, CConnman& connman); From 802c0064b4e31e610dc3c48ea903f01475a2f5e4 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Wed, 23 Oct 2019 09:55:06 +0200 Subject: [PATCH 05/12] Only track last seen time instead of first and last seen time (#3165) This avoids timeouts on parts of the network --- src/llmq/quorums_signing_shares.cpp | 17 ++++------------- src/llmq/quorums_signing_shares.h | 5 ++--- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/llmq/quorums_signing_shares.cpp b/src/llmq/quorums_signing_shares.cpp index 1b1f5c1e1e26..92397fae7abf 100644 --- a/src/llmq/quorums_signing_shares.cpp +++ b/src/llmq/quorums_signing_shares.cpp @@ -666,18 +666,10 @@ void CSigSharesManager::ProcessSigShare(NodeId nodeId, const CSigShare& sigShare if (!sigShares.Add(sigShare.GetKey(), sigShare)) { return; } - sigSharesToAnnounce.Add(sigShare.GetKey(), true); - auto it = timeSeenForSessions.find(sigShare.GetSignHash()); - if (it == timeSeenForSessions.end()) { - auto t = GetTimeMillis(); - // insert first-seen and last-seen time - timeSeenForSessions.emplace(sigShare.GetSignHash(), std::make_pair(t, t)); - } else { - // update last-seen time - it->second.second = GetTimeMillis(); - } + // Update the time we've seen the last sigShare + timeSeenForSessions[sigShare.GetSignHash()] = GetTimeMillis(); if (!quorumNodes.empty()) { // don't announce and wait for other nodes to request this share and directly send it to them @@ -1204,10 +1196,9 @@ void CSigSharesManager::Cleanup() std::unordered_set timeoutSessions; for (auto& p : timeSeenForSessions) { auto& signHash = p.first; - int64_t firstSeenTime = p.second.first; - int64_t lastSeenTime = p.second.second; + int64_t lastSeenTime = p.second; - if (now - firstSeenTime >= SESSION_TOTAL_TIMEOUT || now - lastSeenTime >= SESSION_NEW_SHARES_TIMEOUT) { + if (now - lastSeenTime >= SESSION_NEW_SHARES_TIMEOUT) { timeoutSessions.emplace(signHash); } } diff --git a/src/llmq/quorums_signing_shares.h b/src/llmq/quorums_signing_shares.h index d6a9d10890a2..12dc655e7f66 100644 --- a/src/llmq/quorums_signing_shares.h +++ b/src/llmq/quorums_signing_shares.h @@ -321,7 +321,6 @@ class CSigSharesNodeState class CSigSharesManager : public CRecoveredSigsListener { static const int64_t SESSION_NEW_SHARES_TIMEOUT = 60 * 1000; - static const int64_t SESSION_TOTAL_TIMEOUT = 5 * 60 * 1000; static const int64_t SIG_SHARE_REQUEST_TIMEOUT = 5 * 1000; // we try to keep total message size below 10k @@ -339,8 +338,8 @@ class CSigSharesManager : public CRecoveredSigsListener SigShareMap sigShares; - // stores time of first and last receivedSigShare. Used to detect timeouts - std::unordered_map, StaticSaltedHasher> timeSeenForSessions; + // stores time of last receivedSigShare. Used to detect timeouts + std::unordered_map timeSeenForSessions; std::unordered_map nodeStates; SigShareMap> sigSharesRequested; From 5084bbf9e5c7024936d7bd1820192d9915da9e55 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Fri, 6 Dec 2019 10:05:58 +0100 Subject: [PATCH 06/12] Allow re-signing of IS locks when performing retroactive signing (#3219) * Implement re-signing of InstantSend inputs when TXs come in via blocks * Use GetAdjustedTime instead of GetTimeMillis in CSigSharesManager This allows use of mocktime in tests. * Expose verifiedProRegTxHash in getpeerinfo and implement wait_for_mnauth * Allow to wait for IS and CL to NOT happen * Bump timeout for wait_for_instantlock * Implement tests for retroactive signing of IS and CLs * Add wait_for_tx function to DashTestFramework * Add -whitelist=127.0.0.1 to node0 * Use node3 for isolated block generation * Don't test for non-receival of TXs on node4/node5 --- src/llmq/quorums_signing.cpp | 19 ++++++++++--- src/llmq/quorums_signing.h | 2 +- src/llmq/quorums_signing_shares.cpp | 42 +++++++++++++++++++++++++---- src/llmq/quorums_signing_shares.h | 6 +++-- 4 files changed, 57 insertions(+), 12 deletions(-) diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index 560c90387fd1..424554ec4eae 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -724,7 +724,7 @@ void CSigningManager::UnregisterRecoveredSigsListener(CRecoveredSigsListener* l) recoveredSigsListeners.erase(itRem, recoveredSigsListeners.end()); } -bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) +bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash, bool allowReSign) { auto& params = Params().GetConsensus().llmqs.at(llmqType); @@ -735,24 +735,31 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint { LOCK(cs); - if (db.HasVotedOnId(llmqType, id)) { + bool hasVoted = db.HasVotedOnId(llmqType, id); + if (hasVoted) { uint256 prevMsgHash; db.GetVoteForId(llmqType, id, prevMsgHash); if (msgHash != prevMsgHash) { LogPrintf("CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting on conflicting msgHash=%s\n", __func__, id.ToString(), prevMsgHash.ToString(), msgHash.ToString()); + return false; + } else if (allowReSign) { + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- already voted for id=%s and msgHash=%s. Resigning!\n", __func__, + id.ToString(), prevMsgHash.ToString()); } else { LogPrint(BCLog::LLMQ, "CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting again.\n", __func__, id.ToString(), prevMsgHash.ToString()); + return false; } - return false; } if (db.HasRecoveredSigForId(llmqType, id)) { // no need to sign it if we already have a recovered sig return true; } - db.WriteVoteForId(llmqType, id, msgHash); + if (!hasVoted) { + db.WriteVoteForId(llmqType, id, msgHash); + } } int tipHeight; @@ -776,6 +783,10 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint return false; } + if (allowReSign) { + // make us re-announce all known shares (other nodes might have run into a timeout) + quorumSigSharesManager->ForceReAnnouncement(quorum, llmqType, id, msgHash); + } quorumSigSharesManager->AsyncSign(quorum, id, msgHash); return true; diff --git a/src/llmq/quorums_signing.h b/src/llmq/quorums_signing.h index 23529ffcc2df..4473311a7a64 100644 --- a/src/llmq/quorums_signing.h +++ b/src/llmq/quorums_signing.h @@ -156,7 +156,7 @@ class CSigningManager // public interface void RegisterRecoveredSigsListener(CRecoveredSigsListener* l); void UnregisterRecoveredSigsListener(CRecoveredSigsListener* l); - bool AsyncSignIfMember(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash); + bool AsyncSignIfMember(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash, bool allowReSign = false); bool HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash); bool HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id); bool HasRecoveredSigForSession(const uint256& signHash); diff --git a/src/llmq/quorums_signing_shares.cpp b/src/llmq/quorums_signing_shares.cpp index 92397fae7abf..735c3a934a5e 100644 --- a/src/llmq/quorums_signing_shares.cpp +++ b/src/llmq/quorums_signing_shares.cpp @@ -87,6 +87,13 @@ void CSigSharesInv::Set(uint16_t quorumMember, bool v) inv[quorumMember] = v; } +void CSigSharesInv::SetAll(bool v) +{ + for (size_t i = 0; i < inv.size(); i++) { + inv[i] = v; + } +} + std::string CBatchedSigShares::ToInvString() const { CSigSharesInv inv; @@ -669,7 +676,7 @@ void CSigSharesManager::ProcessSigShare(NodeId nodeId, const CSigShare& sigShare sigSharesToAnnounce.Add(sigShare.GetKey(), true); // Update the time we've seen the last sigShare - timeSeenForSessions[sigShare.GetSignHash()] = GetTimeMillis(); + timeSeenForSessions[sigShare.GetSignHash()] = GetAdjustedTime(); if (!quorumNodes.empty()) { // don't announce and wait for other nodes to request this share and directly send it to them @@ -768,7 +775,7 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_mappindexQuorum->GetBlockHash(), id, msgHash); + auto sigs = sigShares.GetAllForSignHash(signHash); + if (sigs) { + for (auto& p : *sigs) { + // re-announce every sigshare to every node + sigSharesToAnnounce.Add(std::make_pair(signHash, p.first), true); + } + } + for (auto& p : nodeStates) { + CSigSharesNodeState& nodeState = p.second; + auto session = nodeState.GetSessionBySignHash(signHash); + if (!session) { + continue; + } + // pretend that the other node doesn't know about any shares so that we re-announce everything + session->knows.SetAll(false); + // we need to use a new session id as we don't know if the other node has run into a timeout already + session->sendSessionId = (uint32_t)-1; + } +} + void CSigSharesManager::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig) { LOCK(cs); diff --git a/src/llmq/quorums_signing_shares.h b/src/llmq/quorums_signing_shares.h index 12dc655e7f66..2c9eeee5a38c 100644 --- a/src/llmq/quorums_signing_shares.h +++ b/src/llmq/quorums_signing_shares.h @@ -100,6 +100,7 @@ class CSigSharesInv void Init(size_t size); bool IsSet(uint16_t quorumMember) const; void Set(uint16_t quorumMember, bool v); + void SetAll(bool v); void Merge(const CSigSharesInv& inv2); size_t CountSet() const; @@ -320,8 +321,8 @@ class CSigSharesNodeState class CSigSharesManager : public CRecoveredSigsListener { - static const int64_t SESSION_NEW_SHARES_TIMEOUT = 60 * 1000; - static const int64_t SIG_SHARE_REQUEST_TIMEOUT = 5 * 1000; + static const int64_t SESSION_NEW_SHARES_TIMEOUT = 60; + static const int64_t SIG_SHARE_REQUEST_TIMEOUT = 5; // we try to keep total message size below 10k const size_t MAX_MSGS_CNT_QSIGSESANN = 100; @@ -368,6 +369,7 @@ class CSigSharesManager : public CRecoveredSigsListener void AsyncSign(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash); void Sign(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash); + void ForceReAnnouncement(const CQuorumCPtr& quorum, Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash); void HandleNewRecoveredSig(const CRecoveredSig& recoveredSig); From 39d0ed902967f68d4072cfa63613311ae75e0f0e Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Fri, 15 Nov 2024 10:28:54 +0100 Subject: [PATCH 07/12] cherry-pick https://github.com/dashpay/dash/pull/3367 --- src/llmq/quorums_connections.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/llmq/quorums_connections.cpp b/src/llmq/quorums_connections.cpp index f3764d7eeac3..abeec6718b9f 100644 --- a/src/llmq/quorums_connections.cpp +++ b/src/llmq/quorums_connections.cpp @@ -124,9 +124,8 @@ void EnsureLatestQuorumConnections(Consensus::LLMQType llmqType, const CBlockInd continue; } - if (!connman->hasQuorumNodes(llmqType, quorum->pindexQuorum->GetBlockHash())) { - EnsureQuorumConnections(llmqType, quorum->pindexQuorum, myProTxHash); - } + EnsureQuorumConnections(llmqType, quorum->pindexQuorum, myProTxHash); + connmanQuorumsToDelete.erase(quorum->pindexQuorum->GetBlockHash()); } From dac01a9f163b88a168909f1b8d12d1476ff6fb3f Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Fri, 15 Nov 2024 11:46:32 +0100 Subject: [PATCH 08/12] cherry-pick https://github.com/dashpay/dash/pull/2780 --- src/llmq/quorums_chainlocks.cpp | 2 +- src/llmq/quorums_signing.cpp | 2 +- src/net.cpp | 5 ++--- src/net.h | 3 ++- src/version.h | 5 ++++- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/llmq/quorums_chainlocks.cpp b/src/llmq/quorums_chainlocks.cpp index facdadd1d017..2c056cac0cde 100644 --- a/src/llmq/quorums_chainlocks.cpp +++ b/src/llmq/quorums_chainlocks.cpp @@ -144,7 +144,7 @@ void CChainLocksHandler::ProcessNewChainLock(NodeId from, const llmq::CChainLock bestChainLock = clsig; CInv inv(MSG_CLSIG, hash); - g_connman->RelayInv(inv); + g_connman->RelayInv(inv, LLMQS_PROTO_VERSION); auto blockIt = mapBlockIndex.find(clsig.blockHash); if (blockIt == mapBlockIndex.end()) { diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index 424554ec4eae..0507556ed4e4 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -682,7 +682,7 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re CInv inv(MSG_QUORUM_RECOVERED_SIG, recoveredSig.GetHash()); g_connman->ForEachNode([&](CNode* pnode) { - if (pnode->m_wants_recsigs) { + if (pnode->nVersion >= LLMQS_PROTO_VERSION && pnode->m_wants_recsigs) { pnode->PushInventory(inv); } }); diff --git a/src/net.cpp b/src/net.cpp index 951c7444e662..a04687b5b36e 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -23,7 +23,6 @@ #include "primitives/transaction.h" #include "scheduler.h" #include "tiertwo/net_masternodes.h" -#include "validation.h" #ifdef WIN32 #include @@ -2560,14 +2559,14 @@ bool CConnman::DisconnectNode(NodeId id) return false; } -void CConnman::RelayInv(CInv& inv) +void CConnman::RelayInv(CInv& inv, int minProtoVersion) { LOCK(cs_vNodes); for (CNode* pnode : vNodes){ if (!pnode->fSuccessfullyConnected) continue; if ((pnode->nServices == NODE_BLOOM_WITHOUT_MN) && inv.IsMasterNodeType()) continue; if (!pnode->CanRelay()) continue; - if (pnode->nVersion >= ActiveProtocol()) + if (pnode->nVersion >= minProtoVersion) pnode->PushInventory(inv); } } diff --git a/src/net.h b/src/net.h index 4d5b15a70262..2b25df53f4dd 100644 --- a/src/net.h +++ b/src/net.h @@ -23,6 +23,7 @@ #include "uint256.h" #include "utilstrencodings.h" #include "threadinterrupt.h" +#include "validation.h" #include #include @@ -301,7 +302,7 @@ class CConnman // Clears AskFor requests for every known peer void RemoveAskFor(const uint256& invHash, int invType); - void RelayInv(CInv& inv); + void RelayInv(CInv& inv, int minProtoVersion = ActiveProtocol()); bool IsNodeConnected(const CAddress& addr); // Retrieves a connected peer (if connection success). Used only to check peer address availability for now. CNode* ConnectNode(const CAddress& addrConnect); diff --git a/src/version.h b/src/version.h index 03b8e01042f7..7a302212b27b 100644 --- a/src/version.h +++ b/src/version.h @@ -11,7 +11,7 @@ * network protocol versioning */ -static const int PROTOCOL_VERSION = 70927; +static const int PROTOCOL_VERSION = 70928; //! initial proto version, to be increased after version/verack negotiation static const int INIT_PROTO_VERSION = 209; @@ -26,6 +26,9 @@ static const int MIN_BIP155_PROTOCOL_VERSION = 70923; //! Version where MNAUTH was introduced static const int MNAUTH_NODE_VER_VERSION = 70925; +//! Version where LLMQ was introduced +static const int LLMQS_PROTO_VERSION = 70928; + // Make sure that none of the values above collide with // `ADDRV2_FORMAT`. From 36790d2768f7913faf0adaf03284b6e906a74f5f Mon Sep 17 00:00:00 2001 From: Author Alexander Block Date: Fri, 15 Nov 2024 12:22:11 +0100 Subject: [PATCH 09/12] cherry pick https://github.com/dashpay/dash/pull/3368 --- src/llmq/quorums_signing.cpp | 2 +- src/net_processing.cpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index 0507556ed4e4..5468e37c6eed 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -682,7 +682,7 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re CInv inv(MSG_QUORUM_RECOVERED_SIG, recoveredSig.GetHash()); g_connman->ForEachNode([&](CNode* pnode) { - if (pnode->nVersion >= LLMQS_PROTO_VERSION && pnode->m_wants_recsigs) { + if (pnode->nVersion >= LLMQS_PROTO_VERSION && pnode->m_wants_recsigs && !pnode->m_masternode_connection) { pnode->PushInventory(inv); } }); diff --git a/src/net_processing.cpp b/src/net_processing.cpp index a4539fab60cb..8147be8cc3f4 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -880,10 +880,7 @@ bool static AlreadyHave(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(cs_main) static void RelayTransaction(const CTransaction& tx, CConnman* connman) { CInv inv(MSG_TX, tx.GetHash()); - connman->ForEachNode([&inv](CNode* pnode) - { - pnode->PushInventory(inv); - }); + connman->RelayInv(inv); } static void RelayAddress(const CAddress& addr, bool fReachable, CConnman* connman) From d94243909f9d3e4ee8bf3b78298ae984c6ec0136 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Thu, 2 Apr 2020 13:59:05 +0200 Subject: [PATCH 10/12] Merge pull request #3389 from codablock/pr_concentrated_recovery Implement "concentrated recovery" of LLMQ signatures --- src/llmq/quorums_signing.cpp | 2 +- src/llmq/quorums_signing_shares.cpp | 169 +++++++++++++++++++-- src/llmq/quorums_signing_shares.h | 30 +++- src/protocol.cpp | 2 + src/protocol.h | 1 + src/rpc/rpcquorums.cpp | 44 ++++++ src/tiertwo_networksync.cpp | 2 +- test/functional/tiertwo_signing_session.py | 2 +- 8 files changed, 236 insertions(+), 16 deletions(-) diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index 5468e37c6eed..0205bb9b7af4 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -682,7 +682,7 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re CInv inv(MSG_QUORUM_RECOVERED_SIG, recoveredSig.GetHash()); g_connman->ForEachNode([&](CNode* pnode) { - if (pnode->nVersion >= LLMQS_PROTO_VERSION && pnode->m_wants_recsigs && !pnode->m_masternode_connection) { + if (pnode->nVersion >= LLMQS_PROTO_VERSION && pnode->m_wants_recsigs && pnode->CanRelay()) { pnode->PushInventory(inv); } }); diff --git a/src/llmq/quorums_signing_shares.cpp b/src/llmq/quorums_signing_shares.cpp index 735c3a934a5e..1c29314af386 100644 --- a/src/llmq/quorums_signing_shares.cpp +++ b/src/llmq/quorums_signing_shares.cpp @@ -229,6 +229,21 @@ void CSigSharesManager::ProcessMessage(CNode* pfrom, const std::string& strComma return; } + if (strCommand == NetMsgType::QSIGSHARE) { + std::vector sigShares; + vRecv >> sigShares; + + if (sigShares.size() > MAX_MSGS_SIG_SHARES) { + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- too many sigs in QSIGSHARE message. cnt=%d, max=%d, node=%d\n", __func__, sigShares.size(), MAX_MSGS_SIG_SHARES, pfrom->GetId()); + BanNode(pfrom->GetId()); + return; + } + + for (auto& sigShare : sigShares) { + ProcessMessageSigShare(pfrom->GetId(), sigShare, connman); + } + } + if (strCommand == NetMsgType::QSIGSESANN) { std::vector msgs; vRecv >> msgs; @@ -458,6 +473,57 @@ bool CSigSharesManager::ProcessMessageBatchedSigShares(CNode* pfrom, const CBatc return true; } +void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& sigShare, CConnman& connman) +{ + auto quorum = quorumManager->GetQuorum((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash); + if (!quorum) { + return; + } + if (!llmq::utils::IsQuorumActive((Consensus::LLMQType)sigShare.llmqType, quorum->pindexQuorum->GetBlockHash())) { + // quorum is too old + return; + } + if (!quorum->IsMember(activeMasternodeManager->GetProTx())) { + // we're not a member so we can't verify it (we actually shouldn't have received it) + return; + } + if (quorum->quorumVvec == nullptr) { + // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible. node=%d\n", __func__, + quorum->pindexQuorum->GetBlockHash().ToString(), fromId); + return; + } + + if (sigShare.quorumMember >= quorum->members.size()) { + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- quorumMember out of bounds\n", __func__); + BanNode(fromId); + return; + } + // if (!quorum->qc.validMembers[sigShare.quorumMember]) { + // LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- quorumMember not valid\n", __func__); + // BanNode(fromId); + // return; + // } + + { + LOCK(cs); + + if (sigShares.Has(sigShare.GetKey())) { + return; + } + + if (quorumSigningManager->HasRecoveredSigForId((Consensus::LLMQType)sigShare.llmqType, sigShare.id)) { + return; + } + + auto& nodeState = nodeStates[fromId]; + nodeState.pendingIncomingSigShares.Add(sigShare.GetKey(), sigShare); + } + + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, id=%s, msgHash=%s, member=%d, node=%d\n", __func__, + sigShare.GetSignHash().ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), sigShare.quorumMember, fromId); +} + bool CSigSharesManager::PreVerifyBatchedSigShares(NodeId nodeId, const CSigSharesNodeState::SessionInfo& session, const CBatchedSigShares& batchedSigShares, bool& retBan) { retBan = false; @@ -659,9 +725,6 @@ void CSigSharesManager::ProcessSigShare(NodeId nodeId, const CSigShare& sigShare // prepare node set for direct-push in case this is our sig share std::set quorumNodes; - if (sigShare.quorumMember == quorum->GetMemberIndex(activeMasternodeManager->GetProTx())) { - quorumNodes = connman.GetTierTwoConnMan()->getQuorumNodes((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash); - } if (quorumSigningManager->HasRecoveredSigForId(llmqType, sigShare.id)) { return; @@ -678,6 +741,7 @@ void CSigSharesManager::ProcessSigShare(NodeId nodeId, const CSigShare& sigShare // Update the time we've seen the last sigShare timeSeenForSessions[sigShare.GetSignHash()] = GetAdjustedTime(); + // TODO: unreachable if (!quorumNodes.empty()) { // don't announce and wait for other nodes to request this share and directly send it to them // there is no way the other nodes know about this share as this is the one created on this node @@ -771,6 +835,22 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& quorumSigningManager->ProcessRecoveredSig(-1, rs, quorum, connman); } +CDeterministicMNCPtr CSigSharesManager::SelectMemberForRecovery(const CQuorumCPtr& quorum, const uint256& id, int attempt) +{ + assert(attempt < quorum->members.size()); + + std::vector> v; + v.reserve(quorum->members.size()); + for (const auto& dmn : quorum->members) { + auto h = ::SerializeHash(std::make_pair(dmn->proTxHash, id)); + v.emplace_back(h, dmn); + } + std::sort(v.begin(), v.end()); + + return v[attempt].second; +} + +// TODO unused void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map>& sigSharesToRequest) { AssertLockHeld(cs); @@ -867,6 +947,7 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map>& sigSharesToSend) { AssertLockHeld(cs); @@ -919,6 +1000,44 @@ void CSigSharesManager::CollectSigSharesToSend(std::unordered_map>& sigSharesToSend, const std::vector& vNodes) +{ + AssertLockHeld(cs); + + std::unordered_map proTxToNode; + for (const auto& pnode : vNodes) { + if (pnode->verifiedProRegTxHash.IsNull()) { + continue; + } + proTxToNode.emplace(pnode->verifiedProRegTxHash, pnode); + } + + auto curTime = GetTime(); + + for (auto& p : signedSessions) { + if (p.second.attempt >= p.second.quorum->params.recoveryMembers) { + continue; + } + + if (curTime >= p.second.nextAttemptTime) { + p.second.nextAttemptTime = curTime + SEND_FOR_RECOVERY_TIMEOUT; + auto dmn = SelectMemberForRecovery(p.second.quorum, p.second.sigShare.id, p.second.attempt); + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- sending to %s, signHash=%s\n", __func__, + dmn->proTxHash.ToString(), p.second.sigShare.GetSignHash().ToString()); + p.second.attempt++; + + auto it = proTxToNode.find(dmn->proTxHash); + if (it == proTxToNode.end()) { + continue; + } + + auto& m = sigSharesToSend[it->second->GetId()]; + m.emplace_back(p.second.sigShare); + } + } +} + +// TODO unused void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map>& sigSharesToAnnounce) { AssertLockHeld(cs); @@ -974,7 +1093,8 @@ void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map> sigSharesToRequest; - std::unordered_map> sigSharesToSend; + std::unordered_map> sigShareBatchesToSend; + std::unordered_map> sigSharesToSend; std::unordered_map> sigSharesToAnnounce; std::unordered_map> sigSessionAnnouncements; @@ -997,18 +1117,18 @@ bool CSigSharesManager::SendMessages() return session->sendSessionId; }; + std::vector vNodesCopy = g_connman->CopyNodeVector(CConnman::FullyConnectedOnly); + { LOCK(cs); - CollectSigSharesToRequest(sigSharesToRequest); - CollectSigSharesToSend(sigSharesToSend); - CollectSigSharesToAnnounce(sigSharesToAnnounce); + CollectSigSharesToSend(sigSharesToSend, vNodesCopy); for (auto& p : sigSharesToRequest) { for (auto& p2 : p.second) { p2.second.sessionId = addSigSesAnnIfNeeded(p.first, p2.first); } } - for (auto& p : sigSharesToSend) { + for (auto& p : sigShareBatchesToSend) { for (auto& p2 : p.second) { p2.second.sessionId = addSigSesAnnIfNeeded(p.first, p2.first); } @@ -1022,8 +1142,6 @@ bool CSigSharesManager::SendMessages() bool didSend = false; - std::vector vNodesCopy = g_connman->CopyNodeVector(CConnman::FullyConnectedOnly); - for (auto& pnode : vNodesCopy) { CNetMsgMaker msgMaker(pnode->GetSendVersion()); @@ -1067,8 +1185,8 @@ bool CSigSharesManager::SendMessages() } } - auto jt = sigSharesToSend.find(pnode->GetId()); - if (jt != sigSharesToSend.end()) { + auto jt = sigShareBatchesToSend.find(pnode->GetId()); + if (jt != sigShareBatchesToSend.end()) { size_t totalSigsCount = 0; std::vector msgs; for (auto& p : jt->second) { @@ -1109,6 +1227,25 @@ bool CSigSharesManager::SendMessages() didSend = true; } } + + auto lt = sigSharesToSend.find(pnode->GetId()); + if (lt != sigSharesToSend.end()) { + std::vector msgs; + for (auto& sigShare : lt->second) { + LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QSIGSHARE signHash=%s, node=%d\n", + sigShare.GetSignHash().ToString(), pnode->GetId()); + msgs.emplace_back(std::move(sigShare)); + if (msgs.size() == MAX_MSGS_SIG_SHARES) { + g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARE, msgs), false); + msgs.clear(); + didSend = true; + } + } + if (!msgs.empty()) { + g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARE, msgs), false); + didSend = true; + } + } } // looped through all nodes, release them @@ -1275,6 +1412,7 @@ void CSigSharesManager::RemoveSigSharesForSession(const uint256& signHash) sigSharesRequested.EraseAllForSignHash(signHash); sigSharesToAnnounce.EraseAllForSignHash(signHash); sigShares.EraseAllForSignHash(signHash); + signedSessions.erase(signHash); timeSeenForSessions.erase(signHash); } @@ -1413,6 +1551,13 @@ void CSigSharesManager::Sign(const CQuorumCPtr& quorum, const uint256& id, const LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signed sigShare. signHash=%s, id=%s, msgHash=%s, llmqType=%d, quorum=%s, time=%s\n", __func__, signHash.ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), quorum->params.type, quorum->pindexQuorum->GetBlockHash().ToString(), t.count()); ProcessSigShare(-1, sigShare, *g_connman, quorum); + + LOCK(cs); + auto& session = signedSessions[sigShare.GetSignHash()]; + session.sigShare = sigShare; + session.quorum = quorum; + session.nextAttemptTime = 0; + session.attempt = 0; } // causes all known sigShares to be re-announced diff --git a/src/llmq/quorums_signing_shares.h b/src/llmq/quorums_signing_shares.h index 2c9eeee5a38c..40d0921437eb 100644 --- a/src/llmq/quorums_signing_shares.h +++ b/src/llmq/quorums_signing_shares.h @@ -31,7 +31,6 @@ namespace llmq // typedef std::pair SigShareKey; -// this one does not get transmitted over the wire as it is batched inside CBatchedSigShares class CSigShare { public: @@ -55,6 +54,17 @@ class CSigShare assert(!key.first.IsNull()); return key.first; } + + SERIALIZE_METHODS(CSigShare, obj) + { + READWRITE(obj.llmqType); + READWRITE(obj.quorumHash); + READWRITE(obj.quorumMember); + READWRITE(obj.id); + READWRITE(obj.msgHash); + READWRITE(obj.sigShare); + SER_READ(obj, obj.UpdateKey()); + } }; // Nodes will first announce a signing session with a sessionId to be used in all future P2P messages related to that @@ -319,6 +329,16 @@ class CSigSharesNodeState void RemoveSession(const uint256& signHash); }; +class CSignedSession +{ +public: + CSigShare sigShare; + CQuorumCPtr quorum; + + int64_t nextAttemptTime{0}; + int attempt{0}; +}; + class CSigSharesManager : public CRecoveredSigsListener { static const int64_t SESSION_NEW_SHARES_TIMEOUT = 60; @@ -331,6 +351,9 @@ class CSigSharesManager : public CRecoveredSigsListener // 400 is the maximum quorum size, so this is also the maximum number of sigs we need to support const size_t MAX_MSGS_TOTAL_BATCHED_SIGS = 400; + const int64_t SEND_FOR_RECOVERY_TIMEOUT = 1; + const size_t MAX_MSGS_SIG_SHARES = 32; + private: RecursiveMutex cs; @@ -338,6 +361,7 @@ class CSigSharesManager : public CRecoveredSigsListener CThreadInterrupt interruptSigningShare; SigShareMap sigShares; + std::unordered_map signedSessions; // stores time of last receivedSigShare. Used to detect timeouts std::unordered_map timeSeenForSessions; @@ -373,12 +397,15 @@ class CSigSharesManager : public CRecoveredSigsListener void HandleNewRecoveredSig(const CRecoveredSig& recoveredSig); + static CDeterministicMNCPtr SelectMemberForRecovery(const CQuorumCPtr& quorum, const uint256& id, int attempt); + private: // all of these return false when the currently processed message should be aborted (as each message actually contains multiple messages) bool ProcessMessageSigSesAnn(CNode* pfrom, const CSigSesAnn& ann, CConnman& connman); bool ProcessMessageSigSharesInv(CNode* pfrom, const CSigSharesInv& inv, CConnman& connman); bool ProcessMessageGetSigShares(CNode* pfrom, const CSigSharesInv& inv, CConnman& connman); bool ProcessMessageBatchedSigShares(CNode* pfrom, const CBatchedSigShares& batchedSigShares, CConnman& connman); + void ProcessMessageSigShare(NodeId fromId, const CSigShare& sigShare, CConnman& connman); bool VerifySigSharesInv(NodeId from, Consensus::LLMQType llmqType, const CSigSharesInv& inv); bool PreVerifyBatchedSigShares(NodeId nodeId, const CSigSharesNodeState::SessionInfo& session, const CBatchedSigShares& batchedSigShares, bool& retBan); @@ -409,6 +436,7 @@ class CSigSharesManager : public CRecoveredSigsListener bool SendMessages(); void CollectSigSharesToRequest(std::unordered_map>& sigSharesToRequest); void CollectSigSharesToSend(std::unordered_map>& sigSharesToSend); + void CollectSigSharesToSend(std::unordered_map>& sigSharesToSend, const std::vector& vNodes); void CollectSigSharesToAnnounce(std::unordered_map>& sigSharesToAnnounce); bool SignPendingSigShares(); void WorkThreadMain(); diff --git a/src/protocol.cpp b/src/protocol.cpp index b327b3daeb35..f42735c35858 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -65,6 +65,7 @@ const char* QSIGSHARESINV = "qsigsinv"; const char* QGETSIGSHARES = "qgetsigs"; const char* QBSIGSHARES = "qbsigs"; const char* QSIGREC = "qsigrec"; +const char* QSIGSHARE = "qsigshare"; const char* CLSIG = "clsig"; }; // namespace NetMsgType @@ -128,6 +129,7 @@ const static std::string allNetMessageTypes[] = { NetMsgType::QGETSIGSHARES, NetMsgType::QBSIGSHARES, NetMsgType::QSIGREC, + NetMsgType::QSIGSHARE, NetMsgType::CLSIG, }; const static std::vector allNetMessageTypesVec(allNetMessageTypes, allNetMessageTypes + ARRAYLEN(allNetMessageTypes)); diff --git a/src/protocol.h b/src/protocol.h index a0d251bf8706..fe50c53a8e51 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -298,6 +298,7 @@ extern const char* QSIGSHARESINV; extern const char* QGETSIGSHARES; extern const char* QBSIGSHARES; extern const char* QSIGREC; +extern const char* QSIGSHARE; extern const char* CLSIG; }; // namespace NetMsgType diff --git a/src/rpc/rpcquorums.cpp b/src/rpc/rpcquorums.cpp index e0cd374f0374..091f27e60e2c 100644 --- a/src/rpc/rpcquorums.cpp +++ b/src/rpc/rpcquorums.cpp @@ -11,6 +11,7 @@ #include "llmq/quorums_debug.h" #include "llmq/quorums_dkgsession.h" #include "llmq/quorums_signing.h" +#include "llmq/quorums_signing_shares.h" #include "rpc/server.h" #include "validation.h" @@ -343,6 +344,48 @@ UniValue quorumdkgstatus(const JSONRPCRequest& request) return ret; } +UniValue quorumselectquorum(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() != 2) { + throw std::runtime_error( + "quorum selectquorum llmqType \"id\"\n" + "Returns the quorum that would/should sign a request\n" + "\nArguments:\n" + "1. llmqType (int, required) LLMQ type.\n" + "2. \"id\" (string, required) Request id.\n"); + } + + Consensus::LLMQType llmqType = static_cast(request.params[0].get_int()); + if (!Params().GetConsensus().llmqs.count(llmqType)) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); + } + + uint256 id = ParseHashV(request.params[1], "id"); + + int tipHeight; + { + LOCK(cs_main); + tipHeight = chainActive.Height(); + } + + UniValue ret(UniValue::VOBJ); + + auto quorum = llmq::quorumSigningManager->SelectQuorumForSigning(llmqType, tipHeight, id); + if (!quorum) { + throw JSONRPCError(RPC_MISC_ERROR, "no quorums active"); + } + ret.pushKV("quorumHash", quorum->pindexQuorum->GetBlockHash().ToString()); + + UniValue recoveryMembers(UniValue::VARR); + for (int i = 0; i < quorum->params.recoveryMembers; i++) { + auto dmn = llmq::quorumSigSharesManager->SelectMemberForRecovery(quorum, id, i); + recoveryMembers.push_back(dmn->proTxHash.ToString()); + } + ret.pushKV("recoveryMembers", recoveryMembers); + + return ret; +} + UniValue quorumdkgsimerror(const JSONRPCRequest& request) { if (request.fHelp || request.params.size() != 2) { @@ -382,6 +425,7 @@ static const CRPCCommand commands[] = // -------------- ------------------------- --------------------- ------ -------- { "evo", "getminedcommitment", &getminedcommitment, true, {"llmq_type", "quorum_hash"} }, { "evo", "getquorummembers", &getquorummembers, true, {"llmq_type", "quorum_hash"} }, + { "evo", "quorumselectquorum", &quorumselectquorum, true, {"llmq_type", "id"} }, { "evo", "quorumdkgsimerror", &quorumdkgsimerror, true, {"error_type", "rate"} }, { "evo", "quorumdkgstatus", &quorumdkgstatus, true, {"detail_level"} }, { "evo", "listquorums", &listquorums, true, {"count"} }, diff --git a/src/tiertwo_networksync.cpp b/src/tiertwo_networksync.cpp index 383e8b67caaa..26921c4678a5 100644 --- a/src/tiertwo_networksync.cpp +++ b/src/tiertwo_networksync.cpp @@ -72,7 +72,7 @@ bool CMasternodeSync::MessageDispatcher(CNode* pfrom, std::string& strCommand, C } return true; } - if (strCommand == NetMsgType::QSIGSHARESINV || strCommand == NetMsgType::QGETSIGSHARES || strCommand == NetMsgType::QBSIGSHARES || strCommand == NetMsgType::QSIGSESANN) { + if (strCommand == NetMsgType::QSIGSHARESINV || strCommand == NetMsgType::QGETSIGSHARES || strCommand == NetMsgType::QBSIGSHARES || strCommand == NetMsgType::QSIGSESANN || strCommand == NetMsgType::QSIGSHARE) { llmq::quorumSigSharesManager->ProcessMessage(pfrom, strCommand, vRecv, *g_connman); return true; } diff --git a/test/functional/tiertwo_signing_session.py b/test/functional/tiertwo_signing_session.py index 1496ac6bf298..8e2c2b0ae195 100755 --- a/test/functional/tiertwo_signing_session.py +++ b/test/functional/tiertwo_signing_session.py @@ -105,7 +105,7 @@ def run_test(self): for i in [m.idx for m in members]: assert_equal(True, self.nodes[i].hasrecoverysignature(100, id, msgHash)) self.log.info("Threshold signature is still valid after the corresponding quorum went inactive!") - + # TODO: explicitly test also the new concentrated recovery system if __name__ == '__main__': SigningSessionTest().main() From 136f900843bde6aa5a9d25c4071a76712e3be545 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Fri, 15 Nov 2024 19:08:10 +0100 Subject: [PATCH 11/12] cherry-pick https://github.com/dashpay/dash/pull/2833 --- src/llmq/quorums.cpp | 17 ++++++++------- src/llmq/quorums.h | 7 +++---- src/llmq/quorums_signing.cpp | 12 +++++------ src/llmq/quorums_signing_shares.cpp | 32 ++++++++++++++--------------- src/rpc/rpcquorums.cpp | 12 +++++------ 5 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index f1ec5a383166..1ec69dcc7e2f 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -34,7 +34,7 @@ static uint256 MakeQuorumKey(const CQuorum& q) { CHashWriter hw(SER_NETWORK, 0); hw << (uint8_t)q.params.type; - hw << q.pindexQuorum->GetBlockHash(); + hw << q.qc.quorumHash; for (const auto& dmn : q.members) { hw << dmn->proTxHash; } @@ -52,13 +52,12 @@ CQuorum::~CQuorum() } } -void CQuorum::Init(const uint256& _minedBlockHash, const CBlockIndex* _pindexQuorum, const std::vector& _members, const std::vector& _validMembers, const CBLSPublicKey& _quorumPublicKey) +void CQuorum::Init(const CFinalCommitment& _qc, const CBlockIndex* _pindexQuorum, const uint256& _minedBlockHash, const std::vector& _members) { - minedBlockHash = _minedBlockHash; + qc = _qc; pindexQuorum = _pindexQuorum; members = _members; - validMembers = _validMembers; - quorumPublicKey = _quorumPublicKey; + minedBlockHash = _minedBlockHash; } bool CQuorum::IsMember(const uint256& proTxHash) const @@ -75,7 +74,7 @@ bool CQuorum::IsValidMember(const uint256& proTxHash) const { for (size_t i = 0; i < members.size(); i++) { if (members[i]->proTxHash == proTxHash) { - return validMembers[i]; + return qc.validMembers[i]; } } return false; @@ -83,7 +82,7 @@ bool CQuorum::IsValidMember(const uint256& proTxHash) const CBLSPublicKey CQuorum::GetPubKeyShare(size_t memberIdx) const { - if (quorumVvec == nullptr || memberIdx >= members.size() || !validMembers[memberIdx]) { + if (quorumVvec == nullptr || memberIdx >= members.size() || !qc.validMembers[memberIdx]) { return CBLSPublicKey(); } auto& m = members[memberIdx]; @@ -148,7 +147,7 @@ void CQuorum::StartCachePopulatorThread(std::shared_ptr _this) // when then later some other thread tries to get keys, it will be much faster _this->cachePopulatorThread = std::thread(&TraceThread >, "quorum-cachepop", [_this, t] { for (size_t i = 0; i < _this->members.size() && !_this->stopCachePopulatorThread && !ShutdownRequested(); i++) { - if (_this->validMembers[i]) { + if (_this->qc.validMembers[i]) { _this->GetPubKeyShare(i); } } @@ -186,7 +185,7 @@ bool CQuorumManager::BuildQuorumFromCommitment(const CFinalCommitment& qc, const assert(qc.quorumHash == pindexQuorum->GetBlockHash()); auto members = deterministicMNManager->GetAllQuorumMembers((Consensus::LLMQType)qc.llmqType, pindexQuorum); - quorum->Init(minedBlockHash, pindexQuorum, members, qc.validMembers, qc.quorumPublicKey); + quorum->Init(qc, pindexQuorum, minedBlockHash, members); bool hasValidVvec = false; if (quorum->ReadContributions(evoDb)) { diff --git a/src/llmq/quorums.h b/src/llmq/quorums.h index e31d01f4efb5..826a85210075 100644 --- a/src/llmq/quorums.h +++ b/src/llmq/quorums.h @@ -35,11 +35,10 @@ class CQuorum public: const Consensus::LLMQParams& params; - uint256 minedBlockHash; + CFinalCommitment qc; const CBlockIndex* pindexQuorum; + uint256 minedBlockHash; std::vector members; - std::vector validMembers; - CBLSPublicKey quorumPublicKey; // These are only valid when we either participated in the DKG or fully watched it BLSVerificationVectorPtr quorumVvec; @@ -55,7 +54,7 @@ class CQuorum public: CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker) : params(_params), blsCache(_blsWorker), stopCachePopulatorThread(false) {} ~CQuorum(); - void Init(const uint256& minedBlockHash, const CBlockIndex* pindexQuorum, const std::vector& members, const std::vector& validMembers, const CBLSPublicKey& quorumPublicKey); + void Init(const CFinalCommitment& _qc, const CBlockIndex* _pindexQuorum, const uint256& _minedBlockHash, const std::vector& _members); bool IsMember(const uint256& proTxHash) const; bool IsValidMember(const uint256& proTxHash) const; diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index 0205bb9b7af4..bb413f97a78b 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -498,7 +498,7 @@ bool CSigningManager::PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig& recoveredSig.quorumHash.ToString(), nodeId); return false; } - if (!llmq::utils::IsQuorumActive(llmqType, quorum->pindexQuorum->GetBlockHash())) { + if (!llmq::utils::IsQuorumActive(llmqType, quorum->qc.quorumHash)) { return false; } @@ -553,7 +553,7 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify( it = v.erase(it); continue; } - if (!llmq::utils::IsQuorumActive(llmqType, quorum->pindexQuorum->GetBlockHash())) { + if (!llmq::utils::IsQuorumActive(llmqType, quorum->qc.quorumHash)) { LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not active anymore, node=%d\n", __func__, recSig.quorumHash.ToString(), nodeId); it = v.erase(it); @@ -595,7 +595,7 @@ bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman) } const auto& quorum = quorums.at(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.quorumHash)); - batchVerifier.PushMessage(nodeId, recSig.GetHash(), llmq::utils::BuildSignHash(recSig), recSig.sig.Get(), quorum->quorumPublicKey); + batchVerifier.PushMessage(nodeId, recSig.GetHash(), llmq::utils::BuildSignHash(recSig), recSig.sig.Get(), quorum->qc.quorumPublicKey); verifyCount++; } } @@ -863,7 +863,7 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType for (size_t i = 0; i < quorums.size(); i++) { CHashWriter h(SER_NETWORK, 0); h << (uint8_t)llmqType; - h << quorums[i]->pindexQuorum->GetBlockHash(); + h << quorums[i]->qc.quorumHash; h << selectionHash; scores.emplace_back(h.GetHash(), i); } @@ -880,8 +880,8 @@ bool CSigningManager::VerifyRecoveredSig(Consensus::LLMQType llmqType, int signe return false; } - uint256 signHash = llmq::utils::BuildSignHash(llmqParams.type, quorum->pindexQuorum->GetBlockHash(), id, msgHash); - return sig.VerifyInsecure(quorum->quorumPublicKey, signHash); + uint256 signHash = llmq::utils::BuildSignHash(llmqParams.type, quorum->qc.quorumHash, id, msgHash); + return sig.VerifyInsecure(quorum->qc.quorumPublicKey, signHash); } } // namespace llmq \ No newline at end of file diff --git a/src/llmq/quorums_signing_shares.cpp b/src/llmq/quorums_signing_shares.cpp index 1c29314af386..34ac5130998e 100644 --- a/src/llmq/quorums_signing_shares.cpp +++ b/src/llmq/quorums_signing_shares.cpp @@ -479,7 +479,7 @@ void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& s if (!quorum) { return; } - if (!llmq::utils::IsQuorumActive((Consensus::LLMQType)sigShare.llmqType, quorum->pindexQuorum->GetBlockHash())) { + if (!llmq::utils::IsQuorumActive((Consensus::LLMQType)sigShare.llmqType, quorum->qc.quorumHash)) { // quorum is too old return; } @@ -490,7 +490,7 @@ void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& s if (quorum->quorumVvec == nullptr) { // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible. node=%d\n", __func__, - quorum->pindexQuorum->GetBlockHash().ToString(), fromId); + quorum->qc.quorumHash.ToString(), fromId); return; } @@ -499,11 +499,11 @@ void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& s BanNode(fromId); return; } - // if (!quorum->qc.validMembers[sigShare.quorumMember]) { - // LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- quorumMember not valid\n", __func__); - // BanNode(fromId); - // return; - // } + if (!quorum->qc.validMembers[sigShare.quorumMember]) { + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- quorumMember not valid\n", __func__); + BanNode(fromId); + return; + } { LOCK(cs); @@ -528,7 +528,7 @@ bool CSigSharesManager::PreVerifyBatchedSigShares(NodeId nodeId, const CSigShare { retBan = false; - if (!llmq::utils::IsQuorumActive(session.llmqType, session.quorum->pindexQuorum->GetBlockHash())) { + if (!llmq::utils::IsQuorumActive(session.llmqType, session.quorum->qc.quorumHash)) { // quorum is too old return false; } @@ -557,7 +557,7 @@ bool CSigSharesManager::PreVerifyBatchedSigShares(NodeId nodeId, const CSigShare retBan = true; return false; } - if (!session.quorum->validMembers[quorumMember]) { + if (!session.quorum->qc.validMembers[quorumMember]) { LogPrintf("CSigSharesManager::%s -- quorumMember not valid\n", __func__); retBan = true; return false; @@ -778,7 +778,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& auto k = std::make_pair(quorum->params.type, id); - auto signHash = llmq::utils::BuildSignHash(quorum->params.type, quorum->pindexQuorum->GetBlockHash(), id, msgHash); + auto signHash = llmq::utils::BuildSignHash(quorum->params.type, quorum->qc.quorumHash, id, msgHash); auto sigShares = this->sigShares.GetAllForSignHash(signHash); if (!sigShares) { return; @@ -812,7 +812,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& CRecoveredSig rs; rs.llmqType = quorum->params.type; - rs.quorumHash = quorum->pindexQuorum->GetBlockHash(); + rs.quorumHash = quorum->qc.quorumHash; rs.id = id; rs.msgHash = msgHash; rs.sig.Set(recoveredSig); @@ -823,7 +823,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& // verification because this is unbatched and thus slow verification that happens here. if (((recoveredSigsCounter++) % 100) == 0) { auto signHash = llmq::utils::BuildSignHash(rs); - bool valid = recoveredSig.VerifyInsecure(quorum->quorumPublicKey, signHash); + bool valid = recoveredSig.VerifyInsecure(quorum->qc.quorumPublicKey, signHash); if (!valid) { // this should really not happen as we have verified all signature shares before LogPrintf("CSigSharesManager::%s -- own recovered signature is invalid. id=%s, msgHash=%s\n", __func__, @@ -1521,7 +1521,7 @@ void CSigSharesManager::Sign(const CQuorumCPtr& quorum, const uint256& id, const CBLSSecretKey skShare = quorum->GetSkShare(); if (!skShare.IsValid()) { - LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have our skShare for quorum %s\n", __func__, quorum->pindexQuorum->GetBlockHash().ToString()); + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have our skShare for quorum %s\n", __func__, quorum->qc.quorumHash.ToString()); return; } @@ -1533,7 +1533,7 @@ void CSigSharesManager::Sign(const CQuorumCPtr& quorum, const uint256& id, const CSigShare sigShare; sigShare.llmqType = quorum->params.type; - sigShare.quorumHash = quorum->pindexQuorum->GetBlockHash(); + sigShare.quorumHash = quorum->qc.quorumHash; sigShare.id = id; sigShare.msgHash = msgHash; sigShare.quorumMember = (uint16_t)memberIdx; @@ -1549,7 +1549,7 @@ void CSigSharesManager::Sign(const CQuorumCPtr& quorum, const uint256& id, const sigShare.UpdateKey(); LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signed sigShare. signHash=%s, id=%s, msgHash=%s, llmqType=%d, quorum=%s, time=%s\n", __func__, - signHash.ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), quorum->params.type, quorum->pindexQuorum->GetBlockHash().ToString(), t.count()); + signHash.ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), quorum->params.type, quorum->qc.quorumHash.ToString(), t.count()); ProcessSigShare(-1, sigShare, *g_connman, quorum); LOCK(cs); @@ -1564,7 +1564,7 @@ void CSigSharesManager::Sign(const CQuorumCPtr& quorum, const uint256& id, const void CSigSharesManager::ForceReAnnouncement(const CQuorumCPtr& quorum, Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) { LOCK(cs); - auto signHash = llmq::utils::BuildSignHash(llmqType, quorum->pindexQuorum->GetBlockHash(), id, msgHash); + auto signHash = llmq::utils::BuildSignHash(llmqType, quorum->qc.quorumHash, id, msgHash); auto sigs = sigShares.GetAllForSignHash(signHash); if (sigs) { for (auto& p : *sigs) { diff --git a/src/rpc/rpcquorums.cpp b/src/rpc/rpcquorums.cpp index 091f27e60e2c..c1339a856989 100644 --- a/src/rpc/rpcquorums.cpp +++ b/src/rpc/rpcquorums.cpp @@ -141,7 +141,7 @@ UniValue listquorums(const JSONRPCRequest& request) auto quorums = llmq::quorumManager->ScanQuorums(p.first, chainActive.Tip(), count); for (auto& q : quorums) { - v.push_back(q->pindexQuorum->GetBlockHash().ToString()); + v.push_back(q->qc.quorumHash.ToString()); } ret.pushKV(p.second.name, v); @@ -201,15 +201,15 @@ UniValue getquoruminfo(const JSONRPCRequest& request) UniValue ret(UniValue::VOBJ); ret.pushKV("height", quorum->pindexQuorum->nHeight); - ret.pushKV("quorumHash", quorum->pindexQuorum->GetBlockHash().ToString()); + ret.pushKV("quorumHash", quorum->qc.quorumHash.ToString()); UniValue membersArr(UniValue::VARR); for (size_t i = 0; i < quorum->members.size(); i++) { auto& dmn = quorum->members[i]; UniValue mo(UniValue::VOBJ); mo.pushKV("proTxHash", dmn->proTxHash.ToString()); - mo.pushKV("valid", quorum->validMembers[i]); - if (quorum->validMembers[i]) { + mo.pushKV("valid", quorum->qc.validMembers[i]); + if (quorum->qc.validMembers[i]) { CBLSPublicKey pubKey = quorum->GetPubKeyShare(i); if (pubKey.IsValid()) { mo.pushKV("pubKeyShare", pubKey.ToString()); @@ -219,7 +219,7 @@ UniValue getquoruminfo(const JSONRPCRequest& request) } ret.pushKV("members", membersArr); - ret.pushKV("quorumPublicKey", quorum->quorumPublicKey.ToString()); + ret.pushKV("quorumPublicKey", quorum->qc.quorumPublicKey.ToString()); CBLSSecretKey skShare = quorum->GetSkShare(); if (includeSkShare && skShare.IsValid()) { ret.pushKV("secretKeyShare", skShare.ToString()); @@ -374,7 +374,7 @@ UniValue quorumselectquorum(const JSONRPCRequest& request) if (!quorum) { throw JSONRPCError(RPC_MISC_ERROR, "no quorums active"); } - ret.pushKV("quorumHash", quorum->pindexQuorum->GetBlockHash().ToString()); + ret.pushKV("quorumHash", quorum->qc.quorumHash.ToString()); UniValue recoveryMembers(UniValue::VARR); for (int i = 0; i < quorum->params.recoveryMembers; i++) { From a85b4501b174a5ab109fed0dd17a3dae8fafa318 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Wed, 8 Apr 2020 22:19:02 +0200 Subject: [PATCH 12/12] Merge pull request #3399 from codablock/pr_speedups2 Avoid unnecessary processing/verification of reconstructed recovered signatures --- src/llmq/quorums_signing.cpp | 6 ++++-- src/llmq/quorums_signing_shares.cpp | 9 ++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index bb413f97a78b..7380e09bf0f2 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -432,8 +432,10 @@ CSigningManager::CSigningManager(CDBWrapper& llmqDb, bool fMemory) : db(llmqDb) bool CSigningManager::AlreadyHave(const CInv& inv) { - LOCK(cs); - return inv.type == MSG_QUORUM_RECOVERED_SIG && db.HasRecoveredSigForHash(inv.hash); + if (inv.type != MSG_QUORUM_RECOVERED_SIG) { + return false; + } + return db.HasRecoveredSigForHash(inv.hash); } bool CSigningManager::GetRecoveredSigForGetData(const uint256& hash, CRecoveredSig& ret) diff --git a/src/llmq/quorums_signing_shares.cpp b/src/llmq/quorums_signing_shares.cpp index 34ac5130998e..d23c2f7291f4 100644 --- a/src/llmq/quorums_signing_shares.cpp +++ b/src/llmq/quorums_signing_shares.cpp @@ -639,6 +639,7 @@ bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman) // which are not craftable by individual entities, making the rogue public key attack impossible CBLSBatchVerifier batchVerifier(false, true); + cxxtimer::Timer prepareTimer(true); size_t verifyCount = 0; for (auto& p : sigSharesByNodes) { auto nodeId = p.first; @@ -671,12 +672,13 @@ bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman) verifyCount++; } } + prepareTimer.stop(); cxxtimer::Timer verifyTimer(true); batchVerifier.Verify(); verifyTimer.stop(); - LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- verified sig shares. count=%d, vt=%d, nodes=%d\n", __func__, verifyCount, verifyTimer.count(), sigSharesByNodes.size()); + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- verified sig shares. count=%d, pt=%d, vt=%d, nodes=%d\n", __func__, verifyCount, prepareTimer.count(), verifyTimer.count(), sigSharesByNodes.size()); for (auto& p : sigSharesByNodes) { auto nodeId = p.first; @@ -1022,10 +1024,11 @@ void CSigSharesManager::CollectSigSharesToSend(std::unordered_map= p.second.nextAttemptTime) { p.second.nextAttemptTime = curTime + SEND_FOR_RECOVERY_TIMEOUT; auto dmn = SelectMemberForRecovery(p.second.quorum, p.second.sigShare.id, p.second.attempt); - LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- sending to %s, signHash=%s\n", __func__, - dmn->proTxHash.ToString(), p.second.sigShare.GetSignHash().ToString()); p.second.attempt++; + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, sending to %s, attempt=%d\n", __func__, + p.second.sigShare.GetSignHash().ToString(), dmn->proTxHash.ToString(), p.second.attempt); + auto it = proTxToNode.find(dmn->proTxHash); if (it == proTxToNode.end()) { continue;