From c1f756fd90ba6205211b733a59c93d91e27139b5 Mon Sep 17 00:00:00 2001 From: Alexander Block Date: Thu, 13 Jun 2019 11:01:26 +0200 Subject: [PATCH] Multiple speed optimizations for deterministic MN list handling (#2972) * Generalize CBLSLazyWrapper so that it can be used of pubkeys and secret keys * Implement == and != operators for CBLSLazyWrapper * Implement cached hash for CBLSLazyWrapper * Use CBLSLazyPublicKey for CDeterministicMNState::pubKeyOperator * Speed up GetProjectedMNPayees by sorting the MN list by last paid Instead of updating a temporary list for each projected height and calling GetMNPayee() on it. * Cache intermediate lists in GetListForBlock This avoids re-loading and applying diffs again and again. * Only update masternode list UI max once every 3 seconds This avoids updating the UI on every block, which turned out to be very expensive. * Fix compilation * Drop time restrictions for mn list update in ClientModel They are fully handled by MasternodeList now. --- src/bls/bls.cpp | 27 ------- src/bls/bls.h | 107 +++++++++++++++++++++---- src/evo/deterministicmns.cpp | 43 +++++----- src/evo/deterministicmns.h | 6 +- src/evo/mnauth.cpp | 2 +- src/evo/providertx.cpp | 4 +- src/evo/simplifiedmns.cpp | 4 +- src/evo/simplifiedmns.h | 2 +- src/governance-object.cpp | 4 +- src/governance-vote.cpp | 2 +- src/instantx.cpp | 2 +- src/llmq/quorums_chainlocks.cpp | 2 +- src/llmq/quorums_commitment.cpp | 2 +- src/llmq/quorums_dkgsession.cpp | 4 +- src/llmq/quorums_dkgsessionhandler.cpp | 4 +- src/llmq/quorums_instantsend.cpp | 4 +- src/llmq/quorums_signing.cpp | 8 +- src/llmq/quorums_signing_shares.cpp | 12 +-- src/net_processing.cpp | 2 +- src/privatesend-client.cpp | 2 +- src/privatesend-server.cpp | 2 +- src/qt/clientmodel.cpp | 9 +-- src/qt/masternodelist.cpp | 63 +++++++++------ src/qt/masternodelist.h | 9 ++- src/rpc/masternode.cpp | 6 +- src/rpc/rpcevo.cpp | 6 +- src/test/evo_simplifiedmns_tests.cpp | 2 +- src/txmempool.cpp | 8 +- 28 files changed, 204 insertions(+), 144 deletions(-) diff --git a/src/bls/bls.cpp b/src/bls/bls.cpp index bcf3d7ad1..bb44f5029 100644 --- a/src/bls/bls.cpp +++ b/src/bls/bls.cpp @@ -424,33 +424,6 @@ bool CBLSSignature::Recover(const std::vector& sigs, const std::v } #ifndef BUILD_BITCOIN_INTERNAL -void CBLSLazySignature::SetSig(const CBLSSignature& _sig) -{ - std::unique_lock l(mutex); - bufValid = false; - sigInitialized = true; - sig = _sig; -} - -const CBLSSignature& CBLSLazySignature::GetSig() const -{ - std::unique_lock l(mutex); - static CBLSSignature invalidSig; - if (!bufValid && !sigInitialized) { - return invalidSig; - } - if (!sigInitialized) { - sig.SetBuf(buf, sizeof(buf)); - if (!sig.CheckMalleable(buf, sizeof(buf))) { - bufValid = false; - sigInitialized = false; - sig = invalidSig; - } else { - sigInitialized = true; - } - } - return sig; -} static std::once_flag init_flag; static mt_pooled_secure_allocator* secure_allocator_instance; diff --git a/src/bls/bls.h b/src/bls/bls.h index e09998294..ccebca3db 100644 --- a/src/bls/bls.h +++ b/src/bls/bls.h @@ -310,29 +310,34 @@ protected: }; #ifndef BUILD_BITCOIN_INTERNAL -class CBLSLazySignature +template +class CBLSLazyWrapper { private: mutable std::mutex mutex; - mutable char buf[BLS_CURVE_SIG_SIZE]; + mutable char buf[BLSObject::SerSize]; mutable bool bufValid{false}; - mutable CBLSSignature sig; - mutable bool sigInitialized{false}; + mutable BLSObject obj; + mutable bool objInitialized{false}; + + mutable uint256 hash; public: - CBLSLazySignature() + CBLSLazyWrapper() { memset(buf, 0, sizeof(buf)); + // the all-zero buf is considered a valid buf, but the resulting object will return false for IsValid + bufValid = true; } - CBLSLazySignature(const CBLSLazySignature& r) + CBLSLazyWrapper(const CBLSLazyWrapper& r) { *this = r; } - CBLSLazySignature& operator=(const CBLSLazySignature& r) + CBLSLazyWrapper& operator=(const CBLSLazyWrapper& r) { std::unique_lock l(r.mutex); bufValid = r.bufValid; @@ -341,12 +346,13 @@ public: } else { memset(buf, 0, sizeof(buf)); } - sigInitialized = r.sigInitialized; - if (r.sigInitialized) { - sig = r.sig; + objInitialized = r.objInitialized; + if (r.objInitialized) { + obj = r.obj; } else { - sig.Reset(); + obj.Reset(); } + hash = r.hash; return *this; } @@ -354,12 +360,13 @@ public: inline void Serialize(Stream& s) const { std::unique_lock l(mutex); - if (!sigInitialized && !bufValid) { - throw std::ios_base::failure("sig and buf not initialized"); + if (!objInitialized && !bufValid) { + throw std::ios_base::failure("obj and buf not initialized"); } if (!bufValid) { - sig.GetBuf(buf, sizeof(buf)); + obj.GetBuf(buf, sizeof(buf)); bufValid = true; + hash = uint256(); } s.write(buf, sizeof(buf)); } @@ -370,12 +377,78 @@ public: std::unique_lock l(mutex); s.read(buf, sizeof(buf)); bufValid = true; - sigInitialized = false; + objInitialized = false; + hash = uint256(); } - void SetSig(const CBLSSignature& _sig); - const CBLSSignature& GetSig() const; + void Set(const BLSObject& _obj) + { + std::unique_lock l(mutex); + bufValid = false; + objInitialized = true; + obj = _obj; + hash = uint256(); + } + const BLSObject& Get() const + { + std::unique_lock l(mutex); + static BLSObject invalidObj; + if (!bufValid && !objInitialized) { + return invalidObj; + } + if (!objInitialized) { + obj.SetBuf(buf, sizeof(buf)); + if (!obj.CheckMalleable(buf, sizeof(buf))) { + bufValid = false; + objInitialized = false; + obj = invalidObj; + } else { + objInitialized = true; + } + } + return obj; + } + + bool operator==(const CBLSLazyWrapper& r) const + { + if (bufValid && r.bufValid) { + return memcmp(buf, r.buf, sizeof(buf)) == 0; + } + if (objInitialized && r.objInitialized) { + return obj == r.obj; + } + return Get() == r.Get(); + } + + bool operator!=(const CBLSLazyWrapper& r) const + { + return !(*this == r); + } + + uint256 GetHash() const + { + std::unique_lock l(mutex); + if (!bufValid) { + obj.GetBuf(buf, sizeof(buf)); + bufValid = true; + hash = uint256(); + } + if (hash.IsNull()) { + UpdateHash(); + } + return hash; + } +private: + void UpdateHash() const + { + CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); + ss.write(buf, sizeof(buf)); + hash = ss.GetHash(); + } }; +typedef CBLSLazyWrapper CBLSLazySignature; +typedef CBLSLazyWrapper CBLSLazyPublicKey; +typedef CBLSLazyWrapper CBLSLazySecretKey; #endif typedef std::vector BLSIdVector; diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 7bc4e679f..96bb8086a 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -38,7 +38,7 @@ std::string CDeterministicMNState::ToString() const return strprintf("CDeterministicMNState(nRegisteredHeight=%d, nLastPaidHeight=%d, nPoSePenalty=%d, nPoSeRevivedHeight=%d, nPoSeBanHeight=%d, nRevocationReason=%d, " "ownerAddress=%s, pubKeyOperator=%s, votingAddress=%s, addr=%s, payoutAddress=%s, operatorPayoutAddress=%s)", nRegisteredHeight, nLastPaidHeight, nPoSePenalty, nPoSeRevivedHeight, nPoSeBanHeight, nRevocationReason, - CBitcoinAddress(keyIDOwner).ToString(), pubKeyOperator.ToString(), CBitcoinAddress(keyIDVoting).ToString(), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress); + CBitcoinAddress(keyIDOwner).ToString(), pubKeyOperator.Get().ToString(), CBitcoinAddress(keyIDVoting).ToString(), addr.ToStringIPPort(false), payoutAddress, operatorPayoutAddress); } void CDeterministicMNState::ToJson(UniValue& obj) const @@ -60,7 +60,7 @@ void CDeterministicMNState::ToJson(UniValue& obj) const CBitcoinAddress payoutAddress(dest); obj.push_back(Pair("payoutAddress", payoutAddress.ToString())); } - obj.push_back(Pair("pubKeyOperator", pubKeyOperator.ToString())); + obj.push_back(Pair("pubKeyOperator", pubKeyOperator.Get().ToString())); if (ExtractDestination(scriptOperatorPayout, dest)) { CBitcoinAddress operatorPayoutAddress(dest); obj.push_back(Pair("operatorPayoutAddress", operatorPayoutAddress.ToString())); @@ -147,7 +147,7 @@ CDeterministicMNCPtr CDeterministicMNList::GetValidMN(const uint256& proTxHash) CDeterministicMNCPtr CDeterministicMNList::GetMNByOperatorKey(const CBLSPublicKey& pubKey) { for (const auto& p : mnMap) { - if (p.second->pdmnState->pubKeyOperator == pubKey) { + if (p.second->pdmnState->pubKeyOperator.Get() == pubKey) { return p.second; } } @@ -226,21 +226,21 @@ CDeterministicMNCPtr CDeterministicMNList::GetMNPayee() const std::vector CDeterministicMNList::GetProjectedMNPayees(int nCount) const { + if (nCount > GetValidMNsCount()) { + nCount = GetValidMNsCount(); + } + std::vector result; result.reserve(nCount); - CDeterministicMNList tmpMNList = *this; - for (int h = nHeight; h < nHeight + nCount; h++) { - tmpMNList.SetHeight(h); + ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) { + result.emplace_back(dmn); + }); + std::sort(result.begin(), result.end(), [&](const CDeterministicMNCPtr& a, const CDeterministicMNCPtr& b) { + return CompareByLastPaid(a, b); + }); - CDeterministicMNCPtr payee = tmpMNList.GetMNPayee(); - // push the original MN object instead of the one from the temporary list - result.push_back(GetMN(payee->proTxHash)); - - CDeterministicMNStatePtr newState = std::make_shared(*payee->pdmnState); - newState->nLastPaidHeight = h; - tmpMNList.UpdateMN(payee->proTxHash, newState); - } + result.resize(nCount); return result; } @@ -429,7 +429,7 @@ void CDeterministicMNList::AddMN(const CDeterministicMNCPtr& dmn) AddUniqueProperty(dmn, dmn->pdmnState->addr); } AddUniqueProperty(dmn, dmn->pdmnState->keyIDOwner); - if (dmn->pdmnState->pubKeyOperator.IsValid()) { + if (dmn->pdmnState->pubKeyOperator.Get().IsValid()) { AddUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator); } } @@ -457,7 +457,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash) DeleteUniqueProperty(dmn, dmn->pdmnState->addr); } DeleteUniqueProperty(dmn, dmn->pdmnState->keyIDOwner); - if (dmn->pdmnState->pubKeyOperator.IsValid()) { + if (dmn->pdmnState->pubKeyOperator.Get().IsValid()) { DeleteUniqueProperty(dmn, dmn->pdmnState->pubKeyOperator); } mnMap = mnMap.erase(proTxHash); @@ -701,7 +701,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C if (newState->nPoSeBanHeight != -1) { // only revive when all keys are set - if (newState->pubKeyOperator.IsValid() && !newState->keyIDVoting.IsNull() && !newState->keyIDOwner.IsNull()) { + if (newState->pubKeyOperator.Get().IsValid() && !newState->keyIDVoting.IsNull() && !newState->keyIDOwner.IsNull()) { newState->nPoSePenalty = 0; newState->nPoSeBanHeight = -1; newState->nPoSeRevivedHeight = nHeight; @@ -729,12 +729,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C return _state.DoS(100, false, REJECT_INVALID, "bad-protx-hash"); } auto newState = std::make_shared(*dmn->pdmnState); - if (newState->pubKeyOperator != proTx.pubKeyOperator) { + if (newState->pubKeyOperator.Get() != proTx.pubKeyOperator) { // reset all operator related fields and put MN into PoSe-banned state in case the operator key changes newState->ResetOperatorFields(); newState->BanIfNotBanned(nHeight); } - newState->pubKeyOperator = proTx.pubKeyOperator; + newState->pubKeyOperator.Set(proTx.pubKeyOperator); newState->keyIDVoting = proTx.keyIDVoting; newState->scriptPayout = proTx.scriptPayout; @@ -866,12 +866,14 @@ CDeterministicMNList CDeterministicMNManager::GetListForBlock(const uint256& blo } if (evoDb.Read(std::make_pair(DB_LIST_SNAPSHOT, blockHashTmp), snapshot)) { + mnListsCache.emplace(blockHashTmp, snapshot); break; } CDeterministicMNListDiff diff; if (!evoDb.Read(std::make_pair(DB_LIST_DIFF, blockHashTmp), diff)) { snapshot = CDeterministicMNList(blockHashTmp, -1); + mnListsCache.emplace(blockHashTmp, snapshot); break; } @@ -886,9 +888,10 @@ CDeterministicMNList CDeterministicMNManager::GetListForBlock(const uint256& blo snapshot.SetBlockHash(diff.blockHash); snapshot.SetHeight(diff.nHeight); } + + mnListsCache.emplace(diff.blockHash, snapshot); } - mnListsCache.emplace(blockHash, snapshot); return snapshot; } diff --git a/src/evo/deterministicmns.h b/src/evo/deterministicmns.h index 330264015..261ac9bdd 100644 --- a/src/evo/deterministicmns.h +++ b/src/evo/deterministicmns.h @@ -44,7 +44,7 @@ public: uint256 confirmedHashWithProRegTxHash; CKeyID keyIDOwner; - CBLSPublicKey pubKeyOperator; + CBLSLazyPublicKey pubKeyOperator; CKeyID keyIDVoting; CService addr; CScript scriptPayout; @@ -55,7 +55,7 @@ public: CDeterministicMNState(const CProRegTx& proTx) { keyIDOwner = proTx.keyIDOwner; - pubKeyOperator = proTx.pubKeyOperator; + pubKeyOperator.Set(proTx.pubKeyOperator); keyIDVoting = proTx.keyIDVoting; addr = proTx.addr; scriptPayout = proTx.scriptPayout; @@ -89,7 +89,7 @@ public: void ResetOperatorFields() { - pubKeyOperator = CBLSPublicKey(); + pubKeyOperator.Set(CBLSPublicKey()); addr = CService(); scriptOperatorPayout = CScript(); nRevocationReason = CProUpRevTx::REASON_NOT_SPECIFIED; diff --git a/src/evo/mnauth.cpp b/src/evo/mnauth.cpp index 7ecb92154..a8aed3fd4 100644 --- a/src/evo/mnauth.cpp +++ b/src/evo/mnauth.cpp @@ -89,7 +89,7 @@ void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataS signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->sentMNAuthChallenge, !pnode->fInbound)); } - if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator, signHash)) { + if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash)) { LOCK(cs_main); // Same as above, MN seems to not know about his fate yet, so give him a chance to update. If this is a // malicious actor (DoSing us), we'll ban him soon. diff --git a/src/evo/providertx.cpp b/src/evo/providertx.cpp index 47259ce3e..019f427f6 100644 --- a/src/evo/providertx.cpp +++ b/src/evo/providertx.cpp @@ -257,7 +257,7 @@ bool CheckProUpServTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVa if (!CheckInputsHash(tx, ptx, state)) { return false; } - if (!CheckHashSig(ptx, mn->pdmnState->pubKeyOperator, state)) { + if (!CheckHashSig(ptx, mn->pdmnState->pubKeyOperator.Get(), state)) { return false; } } @@ -376,7 +376,7 @@ bool CheckProUpRevTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CVal if (!CheckInputsHash(tx, ptx, state)) return false; - if (!CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator, state)) + if (!CheckHashSig(ptx, dmn->pdmnState->pubKeyOperator.Get(), state)) return false; } diff --git a/src/evo/simplifiedmns.cpp b/src/evo/simplifiedmns.cpp index d43b71741..d23e0f9ce 100644 --- a/src/evo/simplifiedmns.cpp +++ b/src/evo/simplifiedmns.cpp @@ -37,7 +37,7 @@ uint256 CSimplifiedMNListEntry::CalcHash() const std::string CSimplifiedMNListEntry::ToString() const { return strprintf("CSimplifiedMNListEntry(proRegTxHash=%s, confirmedHash=%s, service=%s, pubKeyOperator=%s, votingAddress=%s, isValid=%d)", - proRegTxHash.ToString(), confirmedHash.ToString(), service.ToString(false), pubKeyOperator.ToString(), CBitcoinAddress(keyIDVoting).ToString(), isValid); + proRegTxHash.ToString(), confirmedHash.ToString(), service.ToString(false), pubKeyOperator.Get().ToString(), CBitcoinAddress(keyIDVoting).ToString(), isValid); } void CSimplifiedMNListEntry::ToJson(UniValue& obj) const @@ -47,7 +47,7 @@ void CSimplifiedMNListEntry::ToJson(UniValue& obj) const obj.push_back(Pair("proRegTxHash", proRegTxHash.ToString())); obj.push_back(Pair("confirmedHash", confirmedHash.ToString())); obj.push_back(Pair("service", service.ToString(false))); - obj.push_back(Pair("pubKeyOperator", pubKeyOperator.ToString())); + obj.push_back(Pair("pubKeyOperator", pubKeyOperator.Get().ToString())); obj.push_back(Pair("votingAddress", CBitcoinAddress(keyIDVoting).ToString())); obj.push_back(Pair("isValid", isValid)); } diff --git a/src/evo/simplifiedmns.h b/src/evo/simplifiedmns.h index b9637936b..9a737fe51 100644 --- a/src/evo/simplifiedmns.h +++ b/src/evo/simplifiedmns.h @@ -27,7 +27,7 @@ public: uint256 proRegTxHash; uint256 confirmedHash; CService service; - CBLSPublicKey pubKeyOperator; + CBLSLazyPublicKey pubKeyOperator; CKeyID keyIDVoting; bool isValid; diff --git a/src/governance-object.cpp b/src/governance-object.cpp index 03c3052f7..4dec7fda6 100644 --- a/src/governance-object.cpp +++ b/src/governance-object.cpp @@ -500,8 +500,8 @@ bool CGovernanceObject::IsValidLocally(std::string& strError, bool& fMissingMast } // Check that we have a valid MN signature - if (!CheckSignature(dmn->pdmnState->pubKeyOperator)) { - strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey = " + dmn->pdmnState->pubKeyOperator.ToString(); + if (!CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) { + strError = "Invalid masternode signature for: " + strOutpoint + ", pubkey = " + dmn->pdmnState->pubKeyOperator.Get().ToString(); return false; } diff --git a/src/governance-vote.cpp b/src/governance-vote.cpp index 6a0509432..830e733c4 100644 --- a/src/governance-vote.cpp +++ b/src/governance-vote.cpp @@ -280,7 +280,7 @@ bool CGovernanceVote::IsValid(bool useVotingKey) const if (useVotingKey) { return CheckSignature(dmn->pdmnState->keyIDVoting); } else { - return CheckSignature(dmn->pdmnState->pubKeyOperator); + return CheckSignature(dmn->pdmnState->pubKeyOperator.Get()); } } diff --git a/src/instantx.cpp b/src/instantx.cpp index b43041c4e..849166d28 100644 --- a/src/instantx.cpp +++ b/src/instantx.cpp @@ -1123,7 +1123,7 @@ bool CTxLockVote::CheckSignature() const CBLSSignature sig; sig.SetBuf(vchMasternodeSignature); - if (!sig.IsValid() || !sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator, hash)) { + if (!sig.IsValid() || !sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), hash)) { LogPrintf("CTxLockVote::CheckSignature -- VerifyInsecure() failed\n"); return false; } diff --git a/src/llmq/quorums_chainlocks.cpp b/src/llmq/quorums_chainlocks.cpp index 6e377c221..cdb5d99ac 100644 --- a/src/llmq/quorums_chainlocks.cpp +++ b/src/llmq/quorums_chainlocks.cpp @@ -551,7 +551,7 @@ void CChainLocksHandler::HandleNewRecoveredSig(const llmq::CRecoveredSig& recove clsig.nHeight = lastSignedHeight; clsig.blockHash = lastSignedMsgHash; - clsig.sig = recoveredSig.sig.GetSig(); + clsig.sig = recoveredSig.sig.Get(); } ProcessNewChainLock(-1, clsig, ::SerializeHash(clsig)); } diff --git a/src/llmq/quorums_commitment.cpp b/src/llmq/quorums_commitment.cpp index 83d9c7727..5f84ab942 100644 --- a/src/llmq/quorums_commitment.cpp +++ b/src/llmq/quorums_commitment.cpp @@ -88,7 +88,7 @@ bool CFinalCommitment::Verify(const std::vector& members, if (!signers[i]) { continue; } - memberPubKeys.emplace_back(members[i]->pdmnState->pubKeyOperator); + memberPubKeys.emplace_back(members[i]->pdmnState->pubKeyOperator.Get()); } if (!membersSig.VerifySecureAggregated(memberPubKeys, commitmentHash)) { diff --git a/src/llmq/quorums_dkgsession.cpp b/src/llmq/quorums_dkgsession.cpp index ab844f5f6..1cfd343d3 100644 --- a/src/llmq/quorums_dkgsession.cpp +++ b/src/llmq/quorums_dkgsession.cpp @@ -187,7 +187,7 @@ void CDKGSession::SendContributions(CDKGPendingMessages& pendingMessages) skContrib.MakeNewKey(); } - if (!qc.contributions->Encrypt(i, m->dmn->pdmnState->pubKeyOperator, skContrib, PROTOCOL_VERSION)) { + if (!qc.contributions->Encrypt(i, m->dmn->pdmnState->pubKeyOperator.Get(), skContrib, PROTOCOL_VERSION)) { logger.Batch("failed to encrypt contribution for %s", m->dmn->proTxHash.ToString()); return; } @@ -1219,7 +1219,7 @@ std::vector CDKGSession::FinalizeCommitments() fqc.signers[signerIndex] = true; aggSigs.emplace_back(qc.sig); - aggPks.emplace_back(m->dmn->pdmnState->pubKeyOperator); + aggPks.emplace_back(m->dmn->pdmnState->pubKeyOperator.Get()); signerIds.emplace_back(m->id); thresholdSigs.emplace_back(qc.quorumSig); diff --git a/src/llmq/quorums_dkgsessionhandler.cpp b/src/llmq/quorums_dkgsessionhandler.cpp index eb60d81d4..938b2fe7d 100644 --- a/src/llmq/quorums_dkgsessionhandler.cpp +++ b/src/llmq/quorums_dkgsessionhandler.cpp @@ -313,7 +313,7 @@ std::set BatchVerifyMessageSigs(CDKGSession& session, const std::vector< break; } - pubKeys.emplace_back(member->dmn->pdmnState->pubKeyOperator); + pubKeys.emplace_back(member->dmn->pdmnState->pubKeyOperator.Get()); messageHashes.emplace_back(msgHash); } if (!revertToSingleVerification) { @@ -353,7 +353,7 @@ std::set BatchVerifyMessageSigs(CDKGSession& session, const std::vector< const auto& msg = *p.second; auto member = session.GetMember(msg.proTxHash); - bool valid = msg.sig.VerifyInsecure(member->dmn->pdmnState->pubKeyOperator, msg.GetSignHash()); + bool valid = msg.sig.VerifyInsecure(member->dmn->pdmnState->pubKeyOperator.Get(), msg.GetSignHash()); if (!valid) { ret.emplace(p.first); } diff --git a/src/llmq/quorums_instantsend.cpp b/src/llmq/quorums_instantsend.cpp index f27049a1d..fc2c7dd5f 100644 --- a/src/llmq/quorums_instantsend.cpp +++ b/src/llmq/quorums_instantsend.cpp @@ -747,7 +747,7 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks() continue; } - if (!islock.sig.GetSig().IsValid()) { + if (!islock.sig.Get().IsValid()) { batchVerifier.badSources.emplace(nodeId); continue; } @@ -765,7 +765,7 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks() return false; } uint256 signHash = CLLMQUtils::BuildSignHash(llmqType, quorum->qc.quorumHash, id, islock.txid); - batchVerifier.PushMessage(nodeId, hash, signHash, islock.sig.GetSig(), quorum->qc.quorumPublicKey); + batchVerifier.PushMessage(nodeId, hash, signHash, islock.sig.Get(), quorum->qc.quorumPublicKey); // We can reconstruct the CRecoveredSig objects from the islock and pass it to the signing manager, which // avoids unnecessary double-verification of the signature. We however only do this when verification here diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index 98dd09264..ce14a8e46 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -31,8 +31,8 @@ UniValue CRecoveredSig::ToJson() const ret.push_back(Pair("quorumHash", quorumHash.ToString())); ret.push_back(Pair("id", id.ToString())); ret.push_back(Pair("msgHash", msgHash.ToString())); - ret.push_back(Pair("sig", sig.GetSig().ToString())); - ret.push_back(Pair("hash", sig.GetSig().GetHash().ToString())); + ret.push_back(Pair("sig", sig.Get().ToString())); + ret.push_back(Pair("hash", sig.Get().GetHash().ToString())); return ret; } @@ -575,13 +575,13 @@ bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman) for (auto& recSig : v) { // we didn't verify the lazy signature until now - if (!recSig.sig.GetSig().IsValid()) { + if (!recSig.sig.Get().IsValid()) { batchVerifier.badSources.emplace(nodeId); break; } const auto& quorum = quorums.at(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.quorumHash)); - batchVerifier.PushMessage(nodeId, recSig.GetHash(), CLLMQUtils::BuildSignHash(recSig), recSig.sig.GetSig(), quorum->qc.quorumPublicKey); + batchVerifier.PushMessage(nodeId, recSig.GetHash(), CLLMQUtils::BuildSignHash(recSig), recSig.sig.Get(), quorum->qc.quorumPublicKey); verifyCount++; } } diff --git a/src/llmq/quorums_signing_shares.cpp b/src/llmq/quorums_signing_shares.cpp index 4e9103d5b..a2d4687fd 100644 --- a/src/llmq/quorums_signing_shares.cpp +++ b/src/llmq/quorums_signing_shares.cpp @@ -589,7 +589,7 @@ bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman) // we didn't check this earlier because we use a lazy BLS signature and tried to avoid doing the expensive // deserialization in the message thread - if (!sigShare.sigShare.GetSig().IsValid()) { + if (!sigShare.sigShare.Get().IsValid()) { BanNode(nodeId); // don't process any additional shares from this node break; @@ -605,7 +605,7 @@ bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman) assert(false); } - batchVerifier.PushMessage(nodeId, sigShare.GetKey(), sigShare.GetSignHash(), sigShare.sigShare.GetSig(), pubKeyShare); + batchVerifier.PushMessage(nodeId, sigShare.GetKey(), sigShare.GetSignHash(), sigShare.sigShare.Get(), pubKeyShare); verifyCount++; } } @@ -735,7 +735,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& idsForRecovery.reserve((size_t) quorum->params.threshold); for (auto it = sigShares->begin(); it != sigShares->end() && sigSharesForRecovery.size() < quorum->params.threshold; ++it) { auto& sigShare = it->second; - sigSharesForRecovery.emplace_back(sigShare.sigShare.GetSig()); + sigSharesForRecovery.emplace_back(sigShare.sigShare.Get()); idsForRecovery.emplace_back(CBLSId::FromHash(quorum->members[sigShare.quorumMember]->proTxHash)); } @@ -762,7 +762,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& rs.quorumHash = quorum->qc.quorumHash; rs.id = id; rs.msgHash = msgHash; - rs.sig.SetSig(recoveredSig); + rs.sig.Set(recoveredSig); rs.UpdateHash(); // There should actually be no need to verify the self-recovered signatures as it should always succeed. Let's @@ -1422,8 +1422,8 @@ void CSigSharesManager::Sign(const CQuorumCPtr& quorum, const uint256& id, const sigShare.quorumMember = (uint16_t)memberIdx; uint256 signHash = CLLMQUtils::BuildSignHash(sigShare); - sigShare.sigShare.SetSig(skShare.Sign(signHash)); - if (!sigShare.sigShare.GetSig().IsValid()) { + sigShare.sigShare.Set(skShare.Sign(signHash)); + if (!sigShare.sigShare.Get().IsValid()) { LogPrintf("CSigSharesManager::%s -- failed to sign sigShare. signHash=%s, id=%s, msgHash=%s, time=%s\n", __func__, signHash.ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), t.count()); return; diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 924ed6daa..0e4d6e3fd 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -2174,7 +2174,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr // we have no idea about (e.g we were offline)? How to handle them? } - if (!dstx.CheckSignature(dmn->pdmnState->pubKeyOperator)) { + if (!dstx.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) { LogPrint("privatesend", "DSTX -- CheckSignature() failed for %s\n", hashTx.ToString()); return false; } diff --git a/src/privatesend-client.cpp b/src/privatesend-client.cpp index 24ad5d57e..48e92058b 100644 --- a/src/privatesend-client.cpp +++ b/src/privatesend-client.cpp @@ -66,7 +66,7 @@ void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint); if (!dmn) return; - if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator)) { + if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) { LOCK(cs_main); Misbehaving(pfrom->id, 10); return; diff --git a/src/privatesend-server.cpp b/src/privatesend-server.cpp index 761ec9e1f..7e79c4d9b 100644 --- a/src/privatesend-server.cpp +++ b/src/privatesend-server.cpp @@ -121,7 +121,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint); if (!dmn) return; - if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator)) { + if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) { LOCK(cs_main); Misbehaving(pfrom->id, 10); return; diff --git a/src/qt/clientmodel.cpp b/src/qt/clientmodel.cpp index 271e8275e..2b26ee9c0 100644 --- a/src/qt/clientmodel.cpp +++ b/src/qt/clientmodel.cpp @@ -355,14 +355,7 @@ static void BlockTipChanged(ClientModel *clientmodel, bool initialSync, const CB static void NotifyMasternodeListChanged(ClientModel *clientmodel, const CDeterministicMNList& newList) { - static int64_t nLastMasternodeUpdateNotification = 0; - int64_t now = GetTimeMillis(); - // if we are in-sync, update the UI regardless of last update time - // no need to refresh masternode list/stats as often as blocks etc. - if (masternodeSync.IsBlockchainSynced() || now - nLastMasternodeUpdateNotification > MODEL_UPDATE_DELAY*4*5) { - clientmodel->setMasternodeList(newList); - nLastMasternodeUpdateNotification = now; - } + clientmodel->setMasternodeList(newList); } static void NotifyAdditionalDataSyncProgressChanged(ClientModel *clientmodel, double nSyncProgress) diff --git a/src/qt/masternodelist.cpp b/src/qt/masternodelist.cpp index b1f04036e..3715f6882 100644 --- a/src/qt/masternodelist.cpp +++ b/src/qt/masternodelist.cpp @@ -35,7 +35,9 @@ MasternodeList::MasternodeList(const PlatformStyle* platformStyle, QWidget* pare clientModel(0), walletModel(0), fFilterUpdatedDIP3(true), - nTimeFilterUpdatedDIP3(0) + nTimeFilterUpdatedDIP3(0), + nTimeUpdatedDIP3(0), + mnListChanged(true) { ui->setupUi(this); @@ -89,7 +91,7 @@ void MasternodeList::setClientModel(ClientModel* model) this->clientModel = model; if (model) { // try to update list when masternode count changes - connect(clientModel, SIGNAL(masternodeListChanged()), this, SLOT(updateDIP3ListForced())); + connect(clientModel, SIGNAL(masternodeListChanged()), this, SLOT(handleMasternodeListChanged())); } } @@ -104,37 +106,48 @@ void MasternodeList::showContextMenuDIP3(const QPoint& point) if (item) contextMenuDIP3->exec(QCursor::pos()); } +void MasternodeList::handleMasternodeListChanged() +{ + LOCK(cs_dip3list); + mnListChanged = true; +} + void MasternodeList::updateDIP3ListScheduled() { - updateDIP3List(false); + TRY_LOCK(cs_dip3list, fLockAcquired); + if (!fLockAcquired) return; + + if (!clientModel || ShutdownRequested()) { + return; + } + + // To prevent high cpu usage update only once in MASTERNODELIST_FILTER_COOLDOWN_SECONDS seconds + // after filter was last changed unless we want to force the update. + if (fFilterUpdatedDIP3) { + int64_t nSecondsToWait = nTimeFilterUpdatedDIP3 - GetTime() + MASTERNODELIST_FILTER_COOLDOWN_SECONDS; + ui->countLabelDIP3->setText(QString::fromStdString(strprintf("Please wait... %d", nSecondsToWait))); + + if (nSecondsToWait <= 0) { + updateDIP3List(); + fFilterUpdatedDIP3 = false; + } + } else if (mnListChanged) { + int64_t nSecondsToWait = nTimeUpdatedDIP3 - GetTime() + MASTERNODELIST_UPDATE_SECONDS; + + if (nSecondsToWait <= 0) { + updateDIP3List(); + mnListChanged = false; + } + } } -void MasternodeList::updateDIP3ListForced() -{ - updateDIP3List(true); -} - -void MasternodeList::updateDIP3List(bool fForce) +void MasternodeList::updateDIP3List() { if (!clientModel || ShutdownRequested()) { return; } - TRY_LOCK(cs_dip3list, fLockAcquired); - if (!fLockAcquired) return; - - // To prevent high cpu usage update only once in MASTERNODELIST_FILTER_COOLDOWN_SECONDS seconds - // after filter was last changed unless we want to force the update. - if (!fForce) { - if (!fFilterUpdatedDIP3) return; - - int64_t nSecondsToWait = nTimeFilterUpdatedDIP3 - GetTime() + MASTERNODELIST_FILTER_COOLDOWN_SECONDS; - ui->countLabelDIP3->setText(QString::fromStdString(strprintf("Please wait... %d", nSecondsToWait))); - - if (nSecondsToWait > 0) return; - } - - fFilterUpdatedDIP3 = false; + LOCK(cs_dip3list); QString strToFilter; ui->countLabelDIP3->setText("Updating..."); @@ -143,6 +156,8 @@ void MasternodeList::updateDIP3List(bool fForce) ui->tableWidgetMasternodesDIP3->setRowCount(0); auto mnList = clientModel->getMasternodeList(); + nTimeUpdatedDIP3 = GetTime(); + auto projectedPayees = mnList.GetProjectedMNPayees(mnList.GetValidMNsCount()); std::map nextPayments; for (size_t i = 0; i < projectedPayees.size(); i++) { diff --git a/src/qt/masternodelist.h b/src/qt/masternodelist.h index aecfd707f..e4cff4942 100644 --- a/src/qt/masternodelist.h +++ b/src/qt/masternodelist.h @@ -12,7 +12,7 @@ #include #include -#define MASTERNODELIST_UPDATE_SECONDS 15 +#define MASTERNODELIST_UPDATE_SECONDS 3 #define MASTERNODELIST_FILTER_COOLDOWN_SECONDS 3 namespace Ui @@ -42,6 +42,7 @@ public: private: QMenu* contextMenuDIP3; int64_t nTimeFilterUpdatedDIP3; + int64_t nTimeUpdatedDIP3; bool fFilterUpdatedDIP3; QTimer* timer; @@ -54,9 +55,11 @@ private: QString strCurrentFilterDIP3; + bool mnListChanged; + CDeterministicMNCPtr GetSelectedDIP3MN(); - void updateDIP3List(bool fForce); + void updateDIP3List(); Q_SIGNALS: void doubleClicked(const QModelIndex&); @@ -70,7 +73,7 @@ private Q_SLOTS: void copyProTxHash_clicked(); void copyCollateralOutpoint_clicked(); + void handleMasternodeListChanged(); void updateDIP3ListScheduled(); - void updateDIP3ListForced(); }; #endif // MASTERNODELIST_H diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index d04f1e62a..2f5ad2ece 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -574,7 +574,7 @@ UniValue masternodelist(const JSONRPCRequest& request) CBitcoinAddress(dmn->pdmnState->keyIDOwner).ToString() << " " << CBitcoinAddress(dmn->pdmnState->keyIDVoting).ToString() << " " << collateralAddressStr << " " << - dmn->pdmnState->pubKeyOperator.ToString(); + dmn->pdmnState->pubKeyOperator.Get().ToString(); std::string strInfo = streamInfo.str(); if (strFilter !="" && strInfo.find(strFilter) == std::string::npos && strOutpoint.find(strFilter) == std::string::npos) return; @@ -588,7 +588,7 @@ UniValue masternodelist(const JSONRPCRequest& request) objMN.push_back(Pair("owneraddress", CBitcoinAddress(dmn->pdmnState->keyIDOwner).ToString())); objMN.push_back(Pair("votingaddress", CBitcoinAddress(dmn->pdmnState->keyIDVoting).ToString())); objMN.push_back(Pair("collateraladdress", collateralAddressStr)); - objMN.push_back(Pair("pubkeyoperator", dmn->pdmnState->pubKeyOperator.ToString())); + objMN.push_back(Pair("pubkeyoperator", dmn->pdmnState->pubKeyOperator.Get().ToString())); obj.push_back(Pair(strOutpoint, objMN)); } else if (strMode == "lastpaidblock") { if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return; @@ -605,7 +605,7 @@ UniValue masternodelist(const JSONRPCRequest& request) obj.push_back(Pair(strOutpoint, CBitcoinAddress(dmn->pdmnState->keyIDOwner).ToString())); } else if (strMode == "pubkeyoperator") { if (strFilter !="" && strOutpoint.find(strFilter) == std::string::npos) return; - obj.push_back(Pair(strOutpoint, dmn->pdmnState->pubKeyOperator.ToString())); + obj.push_back(Pair(strOutpoint, dmn->pdmnState->pubKeyOperator.Get().ToString())); } else if (strMode == "status") { std::string strStatus = dmnToStatus(dmn); if (strFilter !="" && strStatus.find(strFilter) == std::string::npos && diff --git a/src/rpc/rpcevo.cpp b/src/rpc/rpcevo.cpp index 7baf1444e..4c5ed8468 100644 --- a/src/rpc/rpcevo.cpp +++ b/src/rpc/rpcevo.cpp @@ -623,7 +623,7 @@ UniValue protx_update_service(const JSONRPCRequest& request) throw std::runtime_error(strprintf("masternode with proTxHash %s not found", ptx.proTxHash.ToString())); } - if (keyOperator.GetPublicKey() != dmn->pdmnState->pubKeyOperator) { + if (keyOperator.GetPublicKey() != dmn->pdmnState->pubKeyOperator.Get()) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("the operator key does not belong to the registered public key")); } @@ -713,7 +713,7 @@ UniValue protx_update_registrar(const JSONRPCRequest& request) if (!dmn) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("masternode %s not found", ptx.proTxHash.ToString())); } - ptx.pubKeyOperator = dmn->pdmnState->pubKeyOperator; + ptx.pubKeyOperator = dmn->pdmnState->pubKeyOperator.Get(); ptx.keyIDVoting = dmn->pdmnState->keyIDVoting; ptx.scriptPayout = dmn->pdmnState->scriptPayout; @@ -808,7 +808,7 @@ UniValue protx_revoke(const JSONRPCRequest& request) throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("masternode %s not found", ptx.proTxHash.ToString())); } - if (keyOperator.GetPublicKey() != dmn->pdmnState->pubKeyOperator) { + if (keyOperator.GetPublicKey() != dmn->pdmnState->pubKeyOperator.Get()) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("the operator key does not belong to the registered public key")); } diff --git a/src/test/evo_simplifiedmns_tests.cpp b/src/test/evo_simplifiedmns_tests.cpp index ca1eabd5e..a1e2b0875 100644 --- a/src/test/evo_simplifiedmns_tests.cpp +++ b/src/test/evo_simplifiedmns_tests.cpp @@ -29,7 +29,7 @@ BOOST_AUTO_TEST_CASE(simplifiedmns_merkleroots) CBLSSecretKey sk; sk.SetBuf(skBuf, sizeof(skBuf)); - smle.pubKeyOperator = sk.GetPublicKey(); + smle.pubKeyOperator.Set(sk.GetPublicKey()); smle.keyIDVoting.SetHex(strprintf("%040x", i)); smle.isValid = true; diff --git a/src/txmempool.cpp b/src/txmempool.cpp index a14ce6aab..779072ba4 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -459,7 +459,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(proTx.proTxHash); assert(dmn); newit->validForProTxKey = ::SerializeHash(dmn->pdmnState->pubKeyOperator); - if (dmn->pdmnState->pubKeyOperator != proTx.pubKeyOperator) { + if (dmn->pdmnState->pubKeyOperator.Get() != proTx.pubKeyOperator) { newit->isKeyChangeProTx = true; } } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) { @@ -470,7 +470,7 @@ bool CTxMemPool::addUnchecked(const uint256& hash, const CTxMemPoolEntry &entry, auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(proTx.proTxHash); assert(dmn); newit->validForProTxKey = ::SerializeHash(dmn->pdmnState->pubKeyOperator); - if (dmn->pdmnState->pubKeyOperator != CBLSPublicKey()) { + if (dmn->pdmnState->pubKeyOperator.Get() != CBLSPublicKey()) { newit->isKeyChangeProTx = true; } } @@ -1294,7 +1294,7 @@ bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const { return true; // i.e. failed to find validated ProTx == conflict } // only allow one operator key change in the mempool - if (dmn->pdmnState->pubKeyOperator != proTx.pubKeyOperator) { + if (dmn->pdmnState->pubKeyOperator.Get() != proTx.pubKeyOperator) { if (hasKeyChangeInMempool(proTx.proTxHash)) { return true; } @@ -1316,7 +1316,7 @@ bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const { return true; // i.e. failed to find validated ProTx == conflict } // only allow one operator key change in the mempool - if (dmn->pdmnState->pubKeyOperator != CBLSPublicKey()) { + if (dmn->pdmnState->pubKeyOperator.Get() != CBLSPublicKey()) { if (hasKeyChangeInMempool(proTx.proTxHash)) { return true; }