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.
This commit is contained in:
Alexander Block 2019-06-13 11:01:26 +02:00
parent 11699f540f
commit c1f756fd90
28 changed files with 204 additions and 144 deletions

View File

@ -424,33 +424,6 @@ bool CBLSSignature::Recover(const std::vector<CBLSSignature>& sigs, const std::v
}
#ifndef BUILD_BITCOIN_INTERNAL
void CBLSLazySignature::SetSig(const CBLSSignature& _sig)
{
std::unique_lock<std::mutex> l(mutex);
bufValid = false;
sigInitialized = true;
sig = _sig;
}
const CBLSSignature& CBLSLazySignature::GetSig() const
{
std::unique_lock<std::mutex> 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<uint8_t>* secure_allocator_instance;

View File

@ -310,29 +310,34 @@ protected:
};
#ifndef BUILD_BITCOIN_INTERNAL
class CBLSLazySignature
template<typename BLSObject>
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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> l(mutex);
bufValid = false;
objInitialized = true;
obj = _obj;
hash = uint256();
}
const BLSObject& Get() const
{
std::unique_lock<std::mutex> 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<std::mutex> 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<CBLSSignature> CBLSLazySignature;
typedef CBLSLazyWrapper<CBLSPublicKey> CBLSLazyPublicKey;
typedef CBLSLazyWrapper<CBLSSecretKey> CBLSLazySecretKey;
#endif
typedef std::vector<CBLSId> BLSIdVector;

View File

@ -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<CDeterministicMNCPtr> CDeterministicMNList::GetProjectedMNPayees(int nCount) const
{
if (nCount > GetValidMNsCount()) {
nCount = GetValidMNsCount();
}
std::vector<CDeterministicMNCPtr> 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<CDeterministicMNState>(*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<CDeterministicMNState>(*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;
}

View File

@ -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;

View File

@ -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.

View File

@ -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;
}

View File

@ -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));
}

View File

@ -27,7 +27,7 @@ public:
uint256 proRegTxHash;
uint256 confirmedHash;
CService service;
CBLSPublicKey pubKeyOperator;
CBLSLazyPublicKey pubKeyOperator;
CKeyID keyIDVoting;
bool isValid;

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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;
}

View File

@ -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));
}

View File

@ -88,7 +88,7 @@ bool CFinalCommitment::Verify(const std::vector<CDeterministicMNCPtr>& 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)) {

View File

@ -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<CFinalCommitment> 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);

View File

@ -313,7 +313,7 @@ std::set<NodeId> 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<NodeId> 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);
}

View File

@ -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

View File

@ -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++;
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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<uint256, int> nextPayments;
for (size_t i = 0; i < projectedPayees.size(); i++) {

View File

@ -12,7 +12,7 @@
#include <QTimer>
#include <QWidget>
#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

View File

@ -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 &&

View File

@ -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"));
}

View File

@ -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;

View File

@ -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;
}