Fix data races triggered by functional tests. (#4247)

Function CWallet::KeepKey requires locking as it has concurrent access to database and member nKeysLeftSinceAutoBackup.

Avoid data race when reading setInventoryTxToSend size by locking the read. If locking happens after the read, the size may change.

Lock cs_mnauth when reading verifiedProRegTxHash.

Make fRPCRunning atomic as it can be read/written from different threads simultaneously.

Make m_masternode_iqr_connection atomic as it can be read/written from different threads simultaneously.

Use a recursive mutex to synchronize concurrent access to quorumVvec.

Make m_masternode_connection atomic as it can be read/written from different threads simultaneously.

Make m_masternode_probe_connection atomic as it can be read/written from different threads simultaneously.

Use a recursive mutex in order to lock access to activeMasterNode.

Use a recursive mutex to synchronize concurrent access to skShare.

Guarded all mnauth fields of a CNode.

Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
gabriel-bjg 2021-07-26 18:52:52 +03:00 committed by GitHub
parent edf0552c0c
commit 41190e9899
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 274 additions and 191 deletions

View File

@ -56,7 +56,7 @@ void CCoinJoinServer::ProcessMessage(CNode* pfrom, const std::string& strCommand
LogPrint(BCLog::COINJOIN, "DSACCEPT -- nDenom %d (%s) txCollateral %s", dsa.nDenom, CCoinJoin::DenominationToString(dsa.nDenom), dsa.txCollateral.ToString()); /* Continued */ LogPrint(BCLog::COINJOIN, "DSACCEPT -- nDenom %d (%s) txCollateral %s", dsa.nDenom, CCoinJoin::DenominationToString(dsa.nDenom), dsa.txCollateral.ToString()); /* Continued */
auto mnList = deterministicMNManager->GetListAtChainTip(); auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetValidMNByCollateral(activeMasternodeInfo.outpoint); auto dmn = WITH_LOCK(activeMasternodeInfoCs, return mnList.GetValidMNByCollateral(activeMasternodeInfo.outpoint));
if (!dmn) { if (!dmn) {
PushStatus(pfrom, STATUS_REJECTED, ERR_MN_LIST, connman); PushStatus(pfrom, STATUS_REJECTED, ERR_MN_LIST, connman);
return; return;
@ -68,7 +68,7 @@ void CCoinJoinServer::ProcessMessage(CNode* pfrom, const std::string& strCommand
if (!lockRecv) return; if (!lockRecv) return;
for (const auto& q : vecCoinJoinQueue) { for (const auto& q : vecCoinJoinQueue) {
if (q.masternodeOutpoint == activeMasternodeInfo.outpoint) { if (WITH_LOCK(activeMasternodeInfoCs, return q.masternodeOutpoint == activeMasternodeInfo.outpoint)) {
// refuse to create another queue this often // refuse to create another queue this often
LogPrint(BCLog::COINJOIN, "DSACCEPT -- last dsq is still in queue, refuse to mix\n"); LogPrint(BCLog::COINJOIN, "DSACCEPT -- last dsq is still in queue, refuse to mix\n");
PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman); PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman);
@ -334,7 +334,7 @@ void CCoinJoinServer::CommitFinalTransaction(CConnman& connman)
// create and sign masternode dstx transaction // create and sign masternode dstx transaction
if (!CCoinJoin::GetDSTX(hashTx)) { if (!CCoinJoin::GetDSTX(hashTx)) {
CCoinJoinBroadcastTx dstxNew(finalTransaction, activeMasternodeInfo.outpoint, GetAdjustedTime()); CCoinJoinBroadcastTx dstxNew(finalTransaction, WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.outpoint), GetAdjustedTime());
dstxNew.Sign(); dstxNew.Sign();
CCoinJoin::AddDSTX(dstxNew); CCoinJoin::AddDSTX(dstxNew);
} }
@ -501,7 +501,7 @@ void CCoinJoinServer::CheckForCompleteQueue(CConnman& connman)
if (nState == POOL_STATE_QUEUE && IsSessionReady()) { if (nState == POOL_STATE_QUEUE && IsSessionReady()) {
SetState(POOL_STATE_ACCEPTING_ENTRIES); SetState(POOL_STATE_ACCEPTING_ENTRIES);
CCoinJoinQueue dsq(nSessionDenom, activeMasternodeInfo.outpoint, GetAdjustedTime(), true); CCoinJoinQueue dsq(nSessionDenom, WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.outpoint), GetAdjustedTime(), true);
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CheckForCompleteQueue -- queue is ready, signing and relaying (%s) " /* Continued */ LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CheckForCompleteQueue -- queue is ready, signing and relaying (%s) " /* Continued */
"with %d participants\n", dsq.ToString(), vecSessionCollaterals.size()); "with %d participants\n", dsq.ToString(), vecSessionCollaterals.size());
dsq.Sign(); dsq.Sign();
@ -708,7 +708,7 @@ bool CCoinJoinServer::CreateNewSession(const CCoinJoinAccept& dsa, PoolMessage&
if (!fUnitTest) { if (!fUnitTest) {
//broadcast that I'm accepting entries, only if it's the first entry through //broadcast that I'm accepting entries, only if it's the first entry through
CCoinJoinQueue dsq(nSessionDenom, activeMasternodeInfo.outpoint, GetAdjustedTime(), false); CCoinJoinQueue dsq(nSessionDenom, WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.outpoint), GetAdjustedTime(), false);
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CreateNewSession -- signing and relaying new queue: %s\n", dsq.ToString()); LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CreateNewSession -- signing and relaying new queue: %s\n", dsq.ToString());
dsq.Sign(); dsq.Sign();
dsq.Relay(connman); dsq.Relay(connman);

View File

@ -50,7 +50,7 @@ bool CCoinJoinQueue::Sign()
uint256 hash = GetSignatureHash(); uint256 hash = GetSignatureHash();
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash); CBLSSignature sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(hash));
if (!sig.IsValid()) { if (!sig.IsValid()) {
return false; return false;
} }
@ -96,7 +96,7 @@ bool CCoinJoinBroadcastTx::Sign()
uint256 hash = GetSignatureHash(); uint256 hash = GetSignatureHash();
CBLSSignature sig = activeMasternodeInfo.blsKeyOperator->Sign(hash); CBLSSignature sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(hash));
if (!sig.IsValid()) { if (!sig.IsValid()) {
return false; return false;
} }

View File

@ -18,31 +18,30 @@
void CMNAuth::PushMNAUTH(CNode* pnode, CConnman& connman) void CMNAuth::PushMNAUTH(CNode* pnode, CConnman& connman)
{ {
LOCK(activeMasternodeInfoCs);
if (!fMasternodeMode || activeMasternodeInfo.proTxHash.IsNull()) { if (!fMasternodeMode || activeMasternodeInfo.proTxHash.IsNull()) {
return; return;
} }
uint256 signHash; uint256 signHash;
{ auto receivedMNAuthChallenge = pnode->GetReceivedMNAuthChallenge();
LOCK(pnode->cs_mnauth); if (receivedMNAuthChallenge.IsNull()) {
if (pnode->receivedMNAuthChallenge.IsNull()) { return;
return; }
} // We include fInbound in signHash to forbid interchanging of challenges by a man in the middle (MITM). This way
// We include fInbound in signHash to forbid interchanging of challenges by a man in the middle (MITM). This way // we protect ourselves against MITM in this form:
// we protect ourselves against MITM in this form: // node1 <- Eve -> node2
// node1 <- Eve -> node2 // It does not protect against:
// It does not protect against: // node1 -> Eve -> node2
// node1 -> Eve -> node2 // This is ok as we only use MNAUTH as a DoS protection and not for sensitive stuff
// This is ok as we only use MNAUTH as a DoS protection and not for sensitive stuff int nOurNodeVersion{PROTOCOL_VERSION};
int nOurNodeVersion{PROTOCOL_VERSION}; if (Params().NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) {
if (Params().NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) { nOurNodeVersion = gArgs.GetArg("-pushversion", PROTOCOL_VERSION);
nOurNodeVersion = gArgs.GetArg("-pushversion", PROTOCOL_VERSION); }
} if (pnode->nVersion < MNAUTH_NODE_VER_VERSION || nOurNodeVersion < MNAUTH_NODE_VER_VERSION) {
if (pnode->nVersion < MNAUTH_NODE_VER_VERSION || nOurNodeVersion < MNAUTH_NODE_VER_VERSION) { signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, receivedMNAuthChallenge, pnode->fInbound));
signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, pnode->receivedMNAuthChallenge, pnode->fInbound)); } else {
} else { signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, receivedMNAuthChallenge, pnode->fInbound, nOurNodeVersion));
signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, pnode->receivedMNAuthChallenge, pnode->fInbound, nOurNodeVersion));
}
} }
CMNAuth mnauth; CMNAuth mnauth;
@ -66,11 +65,7 @@ void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataS
vRecv >> mnauth; vRecv >> mnauth;
// only one MNAUTH allowed // only one MNAUTH allowed
bool fAlreadyHaveMNAUTH = false; bool fAlreadyHaveMNAUTH = !pnode->GetVerifiedProRegTxHash().IsNull();
{
LOCK(pnode->cs_mnauth);
fAlreadyHaveMNAUTH = !pnode->verifiedProRegTxHash.IsNull();
}
if (fAlreadyHaveMNAUTH) { if (fAlreadyHaveMNAUTH) {
LOCK(cs_main); LOCK(cs_main);
Misbehaving(pnode->GetId(), 100, "duplicate mnauth"); Misbehaving(pnode->GetId(), 100, "duplicate mnauth");
@ -108,20 +103,17 @@ void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataS
} }
uint256 signHash; uint256 signHash;
{ int nOurNodeVersion{PROTOCOL_VERSION};
LOCK(pnode->cs_mnauth); if (Params().NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) {
int nOurNodeVersion{PROTOCOL_VERSION}; nOurNodeVersion = gArgs.GetArg("-pushversion", PROTOCOL_VERSION);
if (Params().NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) {
nOurNodeVersion = gArgs.GetArg("-pushversion", PROTOCOL_VERSION);
}
// See comment in PushMNAUTH (fInbound is negated here as we're on the other side of the connection)
if (pnode->nVersion < MNAUTH_NODE_VER_VERSION || nOurNodeVersion < MNAUTH_NODE_VER_VERSION) {
signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->sentMNAuthChallenge, !pnode->fInbound));
} else {
signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->sentMNAuthChallenge, !pnode->fInbound, pnode->nVersion.load()));
}
LogPrint(BCLog::NET_NETCONN, "CMNAuth::%s -- constructed signHash for nVersion %d, peer=%d\n", __func__, pnode->nVersion, pnode->GetId());
} }
// See comment in PushMNAUTH (fInbound is negated here as we're on the other side of the connection)
if (pnode->nVersion < MNAUTH_NODE_VER_VERSION || nOurNodeVersion < MNAUTH_NODE_VER_VERSION) {
signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->GetSentMNAuthChallenge(), !pnode->fInbound));
} else {
signHash = ::SerializeHash(std::make_tuple(dmn->pdmnState->pubKeyOperator, pnode->GetSentMNAuthChallenge(), !pnode->fInbound, pnode->nVersion.load()));
}
LogPrint(BCLog::NET_NETCONN, "CMNAuth::%s -- constructed signHash for nVersion %d, peer=%d\n", __func__, pnode->nVersion, pnode->GetId());
if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash)) { if (!mnauth.sig.VerifyInsecure(dmn->pdmnState->pubKeyOperator.Get(), signHash)) {
LOCK(cs_main); LOCK(cs_main);
@ -147,12 +139,12 @@ void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataS
return; return;
} }
if (pnode2->verifiedProRegTxHash == mnauth.proRegTxHash) { if (pnode2->GetVerifiedProRegTxHash() == mnauth.proRegTxHash) {
if (fMasternodeMode) { if (fMasternodeMode) {
auto deterministicOutbound = llmq::CLLMQUtils::DeterministicOutboundConnection(activeMasternodeInfo.proTxHash, mnauth.proRegTxHash); auto deterministicOutbound = WITH_LOCK(activeMasternodeInfoCs, return llmq::CLLMQUtils::DeterministicOutboundConnection(activeMasternodeInfo.proTxHash, mnauth.proRegTxHash));
LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, deterministicOutbound=%s. peer=%d\n", LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- Masternode %s has already verified as peer %d, deterministicOutbound=%s. peer=%d\n",
mnauth.proRegTxHash.ToString(), pnode2->GetId(), deterministicOutbound.ToString(), pnode->GetId()); mnauth.proRegTxHash.ToString(), pnode2->GetId(), deterministicOutbound.ToString(), pnode->GetId());
if (deterministicOutbound == activeMasternodeInfo.proTxHash) { if (WITH_LOCK(activeMasternodeInfoCs, return deterministicOutbound == activeMasternodeInfo.proTxHash)) {
if (pnode2->fInbound) { if (pnode2->fInbound) {
LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- dropping old inbound, peer=%d\n", pnode2->GetId()); LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- dropping old inbound, peer=%d\n", pnode2->GetId());
pnode2->fDisconnect = true; pnode2->fDisconnect = true;
@ -181,13 +173,10 @@ void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataS
return; return;
} }
{ pnode->SetVerifiedProRegTxHash(mnauth.proRegTxHash);
LOCK(pnode->cs_mnauth); pnode->SetVerifiedPubKeyHash(dmn->pdmnState->pubKeyOperator.GetHash());
pnode->verifiedProRegTxHash = mnauth.proRegTxHash;
pnode->verifiedPubKeyHash = dmn->pdmnState->pubKeyOperator.GetHash();
}
if (!pnode->m_masternode_iqr_connection && connman.IsMasternodeQuorumRelayMember(pnode->verifiedProRegTxHash)) { if (!pnode->m_masternode_iqr_connection && connman.IsMasternodeQuorumRelayMember(pnode->GetVerifiedProRegTxHash())) {
// Tell our peer that we're interested in plain LLMQ recovered signatures. // Tell our peer that we're interested in plain LLMQ recovered signatures.
// Otherwise the peer would only announce/send messages resulting from QRECSIG, // Otherwise the peer would only announce/send messages resulting from QRECSIG,
// e.g. InstantSend locks or ChainLocks. SPV and regular full nodes should not send // e.g. InstantSend locks or ChainLocks. SPV and regular full nodes should not send
@ -209,11 +198,11 @@ void CMNAuth::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList&
} }
g_connman->ForEachNode([&](CNode* pnode) { g_connman->ForEachNode([&](CNode* pnode) {
LOCK(pnode->cs_mnauth); auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (pnode->verifiedProRegTxHash.IsNull()) { if (verifiedProRegTxHash.IsNull()) {
return; return;
} }
auto verifiedDmn = oldMNList.GetMN(pnode->verifiedProRegTxHash); auto verifiedDmn = oldMNList.GetMN(verifiedProRegTxHash);
if (!verifiedDmn) { if (!verifiedDmn) {
return; return;
} }
@ -223,7 +212,7 @@ void CMNAuth::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList&
} else { } else {
auto it = diff.updatedMNs.find(verifiedDmn->GetInternalId()); auto it = diff.updatedMNs.find(verifiedDmn->GetInternalId());
if (it != diff.updatedMNs.end()) { if (it != diff.updatedMNs.end()) {
if ((it->second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && it->second.state.pubKeyOperator.GetHash() != pnode->verifiedPubKeyHash) { if ((it->second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && it->second.state.pubKeyOperator.GetHash() != pnode->GetVerifiedPubKeyHash()) {
doRemove = true; doRemove = true;
} }
} }
@ -231,7 +220,7 @@ void CMNAuth::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList&
if (doRemove) { if (doRemove) {
LogPrint(BCLog::NET_NETCONN, "CMNAuth::NotifyMasternodeListChanged -- Disconnecting MN %s due to key changed/removed, peer=%d\n", LogPrint(BCLog::NET_NETCONN, "CMNAuth::NotifyMasternodeListChanged -- Disconnecting MN %s due to key changed/removed, peer=%d\n",
pnode->verifiedProRegTxHash.ToString(), pnode->GetId()); verifiedProRegTxHash.ToString(), pnode->GetId());
pnode->fDisconnect = true; pnode->fDisconnect = true;
} }
}); });

View File

@ -369,9 +369,12 @@ void PrepareShutdown()
UnregisterValidationInterface(activeMasternodeManager); UnregisterValidationInterface(activeMasternodeManager);
} }
// make sure to clean up BLS keys before global destructors are called (they have allocated from the secure memory pool) {
activeMasternodeInfo.blsKeyOperator.reset(); LOCK(activeMasternodeInfoCs);
activeMasternodeInfo.blsPubKeyOperator.reset(); // make sure to clean up BLS keys before global destructors are called (they have allocated from the secure memory pool)
activeMasternodeInfo.blsKeyOperator.reset();
activeMasternodeInfo.blsPubKeyOperator.reset();
}
#ifndef WIN32 #ifndef WIN32
try { try {
@ -2329,8 +2332,12 @@ bool AppInitMain()
return InitError(_("Invalid masternodeblsprivkey. Please see documentation.")); return InitError(_("Invalid masternodeblsprivkey. Please see documentation."));
} }
fMasternodeMode = true; fMasternodeMode = true;
activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>(keyOperator); {
activeMasternodeInfo.blsPubKeyOperator = std::make_unique<CBLSPublicKey>(activeMasternodeInfo.blsKeyOperator->GetPublicKey()); LOCK(activeMasternodeInfoCs);
activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>(keyOperator);
activeMasternodeInfo.blsPubKeyOperator = std::make_unique<CBLSPublicKey>(
activeMasternodeInfo.blsKeyOperator->GetPublicKey());
}
LogPrintf("MASTERNODE:\n"); LogPrintf("MASTERNODE:\n");
LogPrintf(" blsPubKeyOperator: %s\n", keyOperator.GetPublicKey().ToString()); LogPrintf(" blsPubKeyOperator: %s\n", keyOperator.GetPublicKey().ToString());
} }
@ -2341,11 +2348,14 @@ bool AppInitMain()
RegisterValidationInterface(activeMasternodeManager); RegisterValidationInterface(activeMasternodeManager);
} }
if (activeMasternodeInfo.blsKeyOperator == nullptr) { {
activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>(); LOCK(activeMasternodeInfoCs);
} if (activeMasternodeInfo.blsKeyOperator == nullptr) {
if (activeMasternodeInfo.blsPubKeyOperator == nullptr) { activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>();
activeMasternodeInfo.blsPubKeyOperator = std::make_unique<CBLSPublicKey>(); }
if (activeMasternodeInfo.blsPubKeyOperator == nullptr) {
activeMasternodeInfo.blsPubKeyOperator = std::make_unique<CBLSPublicKey>();
}
} }
// ********************************************************* Step 10b: setup CoinJoin // ********************************************************* Step 10b: setup CoinJoin

View File

@ -61,7 +61,10 @@ void CQuorum::Init(const CFinalCommitmentPtr& _qc, const CBlockIndex* _pindexQuo
bool CQuorum::SetVerificationVector(const BLSVerificationVector& quorumVecIn) bool CQuorum::SetVerificationVector(const BLSVerificationVector& quorumVecIn)
{ {
if (::SerializeHash(quorumVecIn) != qc->quorumVvecHash) { const auto quorumVecInSerialized = ::SerializeHash(quorumVecIn);
LOCK(cs);
if (quorumVecInSerialized != qc->quorumVvecHash) {
return false; return false;
} }
quorumVvec = std::make_shared<BLSVerificationVector>(quorumVecIn); quorumVvec = std::make_shared<BLSVerificationVector>(quorumVecIn);
@ -70,9 +73,10 @@ bool CQuorum::SetVerificationVector(const BLSVerificationVector& quorumVecIn)
bool CQuorum::SetSecretKeyShare(const CBLSSecretKey& secretKeyShare) bool CQuorum::SetSecretKeyShare(const CBLSSecretKey& secretKeyShare)
{ {
if (!secretKeyShare.IsValid() || (secretKeyShare.GetPublicKey() != GetPubKeyShare(GetMemberIndex(activeMasternodeInfo.proTxHash)))) { if (!secretKeyShare.IsValid() || (secretKeyShare.GetPublicKey() != GetPubKeyShare(WITH_LOCK(activeMasternodeInfoCs, return GetMemberIndex(activeMasternodeInfo.proTxHash))))) {
return false; return false;
} }
LOCK(cs);
skShare = secretKeyShare; skShare = secretKeyShare;
return true; return true;
} }
@ -99,15 +103,22 @@ bool CQuorum::IsValidMember(const uint256& proTxHash) const
CBLSPublicKey CQuorum::GetPubKeyShare(size_t memberIdx) const CBLSPublicKey CQuorum::GetPubKeyShare(size_t memberIdx) const
{ {
if (quorumVvec == nullptr || memberIdx >= members.size() || !qc->validMembers[memberIdx]) { LOCK(cs);
if (!HasVerificationVector() || memberIdx >= members.size() || !qc->validMembers[memberIdx]) {
return CBLSPublicKey(); return CBLSPublicKey();
} }
auto& m = members[memberIdx]; auto& m = members[memberIdx];
return blsCache.BuildPubKeyShare(m->proTxHash, quorumVvec, CBLSId(m->proTxHash)); return blsCache.BuildPubKeyShare(m->proTxHash, quorumVvec, CBLSId(m->proTxHash));
} }
const CBLSSecretKey& CQuorum::GetSkShare() const bool CQuorum::HasVerificationVector() const {
LOCK(cs);
return quorumVvec != nullptr;
}
CBLSSecretKey CQuorum::GetSkShare() const
{ {
LOCK(cs);
return skShare; return skShare;
} }
@ -125,7 +136,8 @@ void CQuorum::WriteContributions(CEvoDB& evoDb) const
{ {
uint256 dbKey = MakeQuorumKey(*this); uint256 dbKey = MakeQuorumKey(*this);
if (quorumVvec != nullptr) { LOCK(cs);
if (HasVerificationVector()) {
evoDb.GetRawDB().Write(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), *quorumVvec); evoDb.GetRawDB().Write(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), *quorumVvec);
} }
if (skShare.IsValid()) { if (skShare.IsValid()) {
@ -139,14 +151,14 @@ bool CQuorum::ReadContributions(CEvoDB& evoDb)
BLSVerificationVector qv; BLSVerificationVector qv;
if (evoDb.Read(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), qv)) { if (evoDb.Read(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), qv)) {
quorumVvec = std::make_shared<BLSVerificationVector>(std::move(qv)); WITH_LOCK(cs, quorumVvec = std::make_shared<BLSVerificationVector>(std::move(qv)));
} else { } else {
return false; return false;
} }
// We ignore the return value here as it is ok if this fails. If it fails, it usually means that we are not a // We ignore the return value here as it is ok if this fails. If it fails, it usually means that we are not a
// member of the quorum but observed the whole DKG process to have the quorum verification vector. // member of the quorum but observed the whole DKG process to have the quorum verification vector.
evoDb.Read(std::make_pair(DB_QUORUM_SK_SHARE, dbKey), skShare); WITH_LOCK(cs, evoDb.Read(std::make_pair(DB_QUORUM_SK_SHARE, dbKey), skShare));
return true; return true;
} }
@ -197,8 +209,10 @@ void CQuorumManager::TriggerQuorumDataRecoveryThreads(const CBlockIndex* pIndex)
// First check if we are member of any quorum of this type // First check if we are member of any quorum of this type
bool fWeAreQuorumTypeMember{false}; bool fWeAreQuorumTypeMember{false};
auto proTxHash = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash);
for (const auto& pQuorum : vecQuorums) { for (const auto& pQuorum : vecQuorums) {
if (pQuorum->IsValidMember(activeMasternodeInfo.proTxHash)) { if (pQuorum->IsValidMember(proTxHash)) {
fWeAreQuorumTypeMember = true; fWeAreQuorumTypeMember = true;
break; break;
} }
@ -211,16 +225,16 @@ void CQuorumManager::TriggerQuorumDataRecoveryThreads(const CBlockIndex* pIndex)
} }
uint16_t nDataMask{0}; uint16_t nDataMask{0};
const bool fWeAreQuorumMember = pQuorum->IsValidMember(activeMasternodeInfo.proTxHash); const bool fWeAreQuorumMember = pQuorum->IsValidMember(proTxHash);
const bool fSyncForTypeEnabled = mapQuorumVvecSync.count(pQuorum->qc->llmqType) > 0; const bool fSyncForTypeEnabled = mapQuorumVvecSync.count(pQuorum->qc->llmqType) > 0;
const QvvecSyncMode syncMode = fSyncForTypeEnabled ? mapQuorumVvecSync.at(pQuorum->qc->llmqType) : QvvecSyncMode::Invalid; const QvvecSyncMode syncMode = fSyncForTypeEnabled ? mapQuorumVvecSync.at(pQuorum->qc->llmqType) : QvvecSyncMode::Invalid;
const bool fSyncCurrent = syncMode == QvvecSyncMode::Always || (syncMode == QvvecSyncMode::OnlyIfTypeMember && fWeAreQuorumTypeMember); const bool fSyncCurrent = syncMode == QvvecSyncMode::Always || (syncMode == QvvecSyncMode::OnlyIfTypeMember && fWeAreQuorumTypeMember);
if ((fWeAreQuorumMember || (fSyncForTypeEnabled && fSyncCurrent)) && pQuorum->quorumVvec == nullptr) { if ((fWeAreQuorumMember || (fSyncForTypeEnabled && fSyncCurrent)) && !pQuorum->HasVerificationVector()) {
nDataMask |= llmq::CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR; nDataMask |= llmq::CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR;
} }
if (fWeAreQuorumMember && !pQuorum->skShare.IsValid()) { if (fWeAreQuorumMember && !pQuorum->GetSkShare().IsValid()) {
nDataMask |= llmq::CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS; nDataMask |= llmq::CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS;
} }
@ -266,7 +280,6 @@ void CQuorumManager::EnsureQuorumConnections(Consensus::LLMQType llmqType, const
{ {
const auto& llmq_params = GetLLMQParams(llmqType); const auto& llmq_params = GetLLMQParams(llmqType);
const auto& myProTxHash = activeMasternodeInfo.proTxHash;
auto lastQuorums = ScanQuorums(llmqType, pindexNew, (size_t)llmq_params.keepOldConnections); auto lastQuorums = ScanQuorums(llmqType, pindexNew, (size_t)llmq_params.keepOldConnections);
auto connmanQuorumsToDelete = g_connman->GetMasternodeQuorums(llmqType); auto connmanQuorumsToDelete = g_connman->GetMasternodeQuorums(llmqType);
@ -277,7 +290,7 @@ void CQuorumManager::EnsureQuorumConnections(Consensus::LLMQType llmqType, const
connmanQuorumsToDelete.erase(curDkgBlock); connmanQuorumsToDelete.erase(curDkgBlock);
for (const auto& quorum : lastQuorums) { for (const auto& quorum : lastQuorums) {
if (CLLMQUtils::EnsureQuorumConnections(llmqType, quorum->pindexQuorum, myProTxHash)) { if (CLLMQUtils::EnsureQuorumConnections(llmqType, quorum->pindexQuorum, WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash))) {
continue; continue;
} }
if (connmanQuorumsToDelete.count(quorum->qc->quorumHash) > 0) { if (connmanQuorumsToDelete.count(quorum->qc->quorumHash) > 0) {
@ -339,8 +352,9 @@ bool CQuorumManager::BuildQuorumContributions(const CFinalCommitmentPtr& fqc, co
} }
cxxtimer::Timer t2(true); cxxtimer::Timer t2(true);
LOCK(quorum->cs);
quorum->quorumVvec = blsWorker.BuildQuorumVerificationVector(vvecs); quorum->quorumVvec = blsWorker.BuildQuorumVerificationVector(vvecs);
if (quorum->quorumVvec == nullptr) { if (!quorum->HasVerificationVector()) {
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- failed to build quorumVvec\n", __func__); LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- failed to build quorumVvec\n", __func__);
// without the quorum vvec, there can't be a skShare, so we fail here. Failure is not fatal here, as it still // without the quorum vvec, there can't be a skShare, so we fail here. Failure is not fatal here, as it still
// allows to use the quorum as a non-member (verification through the quorum pub key) // allows to use the quorum as a non-member (verification through the quorum pub key)
@ -371,7 +385,7 @@ bool CQuorumManager::RequestQuorumData(CNode* pFrom, Consensus::LLMQType llmqTyp
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Version must be %d or greater.\n", __func__, LLMQ_DATA_MESSAGES_VERSION); LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Version must be %d or greater.\n", __func__, LLMQ_DATA_MESSAGES_VERSION);
return false; return false;
} }
if (pFrom == nullptr || (pFrom->verifiedProRegTxHash.IsNull() && !pFrom->qwatch)) { if (pFrom == nullptr || (pFrom->GetVerifiedProRegTxHash().IsNull() && !pFrom->qwatch)) {
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- pFrom is neither a verified masternode nor a qwatch connection\n", __func__); LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- pFrom is neither a verified masternode nor a qwatch connection\n", __func__);
return false; return false;
} }
@ -389,7 +403,7 @@ bool CQuorumManager::RequestQuorumData(CNode* pFrom, Consensus::LLMQType llmqTyp
} }
LOCK(cs_data_requests); LOCK(cs_data_requests);
auto key = std::make_pair(pFrom->verifiedProRegTxHash, true); auto key = std::make_pair(pFrom->GetVerifiedProRegTxHash(), true);
auto it = mapQuorumDataRequests.emplace(key, CQuorumDataRequest(llmqType, pQuorumIndex->GetBlockHash(), nDataMask, proTxHash)); auto it = mapQuorumDataRequests.emplace(key, CQuorumDataRequest(llmqType, pQuorumIndex->GetBlockHash(), nDataMask, proTxHash));
if (!it.second && !it.first->second.IsExpired()) { if (!it.second && !it.first->second.IsExpired()) {
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Already requested\n", __func__); LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Already requested\n", __func__);
@ -517,10 +531,13 @@ size_t CQuorumManager::GetQuorumRecoveryStartOffset(const CQuorumCPtr pQuorum, c
}); });
std::sort(vecProTxHashes.begin(), vecProTxHashes.end()); std::sort(vecProTxHashes.begin(), vecProTxHashes.end());
size_t nIndex{0}; size_t nIndex{0};
for (size_t i = 0; i < vecProTxHashes.size(); ++i) { {
if (activeMasternodeInfo.proTxHash == vecProTxHashes[i]) { LOCK(activeMasternodeInfoCs);
nIndex = i; for (size_t i = 0; i < vecProTxHashes.size(); ++i) {
break; if (activeMasternodeInfo.proTxHash == vecProTxHashes[i]) {
nIndex = i;
break;
}
} }
} }
return nIndex % pQuorum->qc->validMembers.size(); return nIndex % pQuorum->qc->validMembers.size();
@ -539,7 +556,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
if (strCommand == NetMsgType::QGETDATA) { if (strCommand == NetMsgType::QGETDATA) {
if (!fMasternodeMode || pFrom == nullptr || (pFrom->verifiedProRegTxHash.IsNull() && !pFrom->qwatch)) { if (!fMasternodeMode || pFrom == nullptr || (pFrom->GetVerifiedProRegTxHash().IsNull() && !pFrom->qwatch)) {
errorHandler("Not a verified masternode or a qwatch connection"); errorHandler("Not a verified masternode or a qwatch connection");
return; return;
} }
@ -556,7 +573,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
{ {
LOCK2(cs_main, cs_data_requests); LOCK2(cs_main, cs_data_requests);
auto key = std::make_pair(pFrom->verifiedProRegTxHash, false); auto key = std::make_pair(pFrom->GetVerifiedProRegTxHash(), false);
auto it = mapQuorumDataRequests.find(key); auto it = mapQuorumDataRequests.find(key);
if (it == mapQuorumDataRequests.end()) { if (it == mapQuorumDataRequests.end()) {
it = mapQuorumDataRequests.emplace(key, request).first; it = mapQuorumDataRequests.emplace(key, request).first;
@ -592,13 +609,12 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
// Check if request wants QUORUM_VERIFICATION_VECTOR data // Check if request wants QUORUM_VERIFICATION_VECTOR data
if (request.GetDataMask() & CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR) { if (request.GetDataMask() & CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR) {
if (!pQuorum->HasVerificationVector()) {
if (!pQuorum->quorumVvec) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_VERIFICATION_VECTOR_MISSING); sendQDATA(CQuorumDataRequest::Errors::QUORUM_VERIFICATION_VECTOR_MISSING);
return; return;
} }
ssResponseData << *pQuorum->quorumVvec; WITH_LOCK(pQuorum->cs, ssResponseData << *pQuorum->quorumVvec);
} }
// Check if request wants ENCRYPTED_CONTRIBUTIONS data // Check if request wants ENCRYPTED_CONTRIBUTIONS data
@ -624,8 +640,8 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
} }
if (strCommand == NetMsgType::QDATA) { if (strCommand == NetMsgType::QDATA) {
auto verifiedProRegTxHash = pFrom->GetVerifiedProRegTxHash();
if ((!fMasternodeMode && !CLLMQUtils::IsWatchQuorumsEnabled()) || pFrom == nullptr || (pFrom->verifiedProRegTxHash.IsNull() && !pFrom->qwatch)) { if ((!fMasternodeMode && !CLLMQUtils::IsWatchQuorumsEnabled()) || pFrom == nullptr || (verifiedProRegTxHash.IsNull() && !pFrom->qwatch)) {
errorHandler("Not a verified masternode or a qwatch connection"); errorHandler("Not a verified masternode or a qwatch connection");
return; return;
} }
@ -635,7 +651,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
{ {
LOCK2(cs_main, cs_data_requests); LOCK2(cs_main, cs_data_requests);
auto it = mapQuorumDataRequests.find(std::make_pair(pFrom->verifiedProRegTxHash, true)); auto it = mapQuorumDataRequests.find(std::make_pair(verifiedProRegTxHash, true));
if (it == mapQuorumDataRequests.end()) { if (it == mapQuorumDataRequests.end()) {
errorHandler("Not requested"); errorHandler("Not requested");
return; return;
@ -682,7 +698,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
// Check if request has ENCRYPTED_CONTRIBUTIONS data // Check if request has ENCRYPTED_CONTRIBUTIONS data
if (request.GetDataMask() & CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS) { if (request.GetDataMask() & CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS) {
if (pQuorum->quorumVvec->size() != pQuorum->params.threshold) { if (WITH_LOCK(pQuorum->cs, return pQuorum->quorumVvec->size() != pQuorum->params.threshold)) {
errorHandler("No valid quorum verification vector available", 0); // Don't bump score because we asked for it errorHandler("No valid quorum verification vector available", 0); // Don't bump score because we asked for it
return; return;
} }
@ -698,8 +714,9 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
BLSSecretKeyVector vecSecretKeys; BLSSecretKeyVector vecSecretKeys;
vecSecretKeys.resize(vecEncrypted.size()); vecSecretKeys.resize(vecEncrypted.size());
auto secret = WITH_LOCK(activeMasternodeInfoCs, return *activeMasternodeInfo.blsKeyOperator);
for (size_t i = 0; i < vecEncrypted.size(); ++i) { for (size_t i = 0; i < vecEncrypted.size(); ++i) {
if (!vecEncrypted[i].Decrypt(memberIdx, *activeMasternodeInfo.blsKeyOperator, vecSecretKeys[i], PROTOCOL_VERSION)) { if (!vecEncrypted[i].Decrypt(memberIdx, secret, vecSecretKeys[i], PROTOCOL_VERSION)) {
errorHandler("Failed to decrypt"); errorHandler("Failed to decrypt");
return; return;
} }
@ -718,7 +735,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
void CQuorumManager::StartCachePopulatorThread(const CQuorumCPtr pQuorum) const void CQuorumManager::StartCachePopulatorThread(const CQuorumCPtr pQuorum) const
{ {
if (pQuorum->quorumVvec == nullptr) { if (!pQuorum->HasVerificationVector()) {
return; return;
} }
@ -771,7 +788,7 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co
vecMemberHashes.reserve(pQuorum->qc->validMembers.size()); vecMemberHashes.reserve(pQuorum->qc->validMembers.size());
for (auto& member : pQuorum->members) { for (auto& member : pQuorum->members) {
if (pQuorum->IsValidMember(member->proTxHash) && member->proTxHash != activeMasternodeInfo.proTxHash) { if (pQuorum->IsValidMember(member->proTxHash) && member->proTxHash != WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash)) {
vecMemberHashes.push_back(member->proTxHash); vecMemberHashes.push_back(member->proTxHash);
} }
} }
@ -781,12 +798,13 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co
while (nDataMask > 0 && !quorumThreadInterrupt) { while (nDataMask > 0 && !quorumThreadInterrupt) {
if (nDataMask & llmq::CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR && pQuorum->quorumVvec != nullptr) { if (nDataMask & llmq::CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR &&
pQuorum->HasVerificationVector()) {
nDataMask &= ~llmq::CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR; nDataMask &= ~llmq::CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR;
printLog("Received quorumVvec"); printLog("Received quorumVvec");
} }
if (nDataMask & llmq::CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS && pQuorum->skShare.IsValid()) { if (nDataMask & llmq::CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS && pQuorum->GetSkShare().IsValid()) {
nDataMask &= ~llmq::CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS; nDataMask &= ~llmq::CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS;
printLog("Received skShare"); printLog("Received skShare");
} }
@ -818,18 +836,19 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co
printLog("Connect"); printLog("Connect");
} }
auto proTxHash = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash);
g_connman->ForEachNode([&](CNode* pNode) { g_connman->ForEachNode([&](CNode* pNode) {
auto verifiedProRegTxHash = pNode->GetVerifiedProRegTxHash();
if (pCurrentMemberHash == nullptr || pNode->verifiedProRegTxHash != *pCurrentMemberHash) { if (pCurrentMemberHash == nullptr || verifiedProRegTxHash != *pCurrentMemberHash) {
return; return;
} }
if (quorumManager->RequestQuorumData(pNode, pQuorum->qc->llmqType, pQuorum->pindexQuorum, nDataMask, activeMasternodeInfo.proTxHash)) { if (quorumManager->RequestQuorumData(pNode, pQuorum->qc->llmqType, pQuorum->pindexQuorum, nDataMask, proTxHash)) {
nTimeLastSuccess = GetAdjustedTime(); nTimeLastSuccess = GetAdjustedTime();
printLog("Requested"); printLog("Requested");
} else { } else {
LOCK(cs_data_requests); LOCK(cs_data_requests);
auto it = mapQuorumDataRequests.find(std::make_pair(pNode->verifiedProRegTxHash, true)); auto it = mapQuorumDataRequests.find(std::make_pair(verifiedProRegTxHash, true));
if (it == mapQuorumDataRequests.end()) { if (it == mapQuorumDataRequests.end()) {
printLog("Failed"); printLog("Failed");
pNode->fDisconnect = true; pNode->fDisconnect = true;

View File

@ -157,16 +157,17 @@ public:
uint256 minedBlockHash; uint256 minedBlockHash;
std::vector<CDeterministicMNCPtr> members; std::vector<CDeterministicMNCPtr> members;
// These are only valid when we either participated in the DKG or fully watched it
BLSVerificationVectorPtr quorumVvec;
CBLSSecretKey skShare;
private: private:
// Recovery of public key shares is very slow, so we start a background thread that pre-populates a cache so that // Recovery of public key shares is very slow, so we start a background thread that pre-populates a cache so that
// the public key shares are ready when needed later // the public key shares are ready when needed later
mutable CBLSWorkerCache blsCache; mutable CBLSWorkerCache blsCache;
mutable std::atomic<bool> fQuorumDataRecoveryThreadRunning{false}; mutable std::atomic<bool> fQuorumDataRecoveryThreadRunning{false};
mutable CCriticalSection cs;
// These are only valid when we either participated in the DKG or fully watched it
BLSVerificationVectorPtr quorumVvec GUARDED_BY(cs);
CBLSSecretKey skShare GUARDED_BY(cs);
public: public:
CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker); CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker);
~CQuorum(); ~CQuorum();
@ -175,12 +176,13 @@ public:
bool SetVerificationVector(const BLSVerificationVector& quorumVecIn); bool SetVerificationVector(const BLSVerificationVector& quorumVecIn);
bool SetSecretKeyShare(const CBLSSecretKey& secretKeyShare); bool SetSecretKeyShare(const CBLSSecretKey& secretKeyShare);
bool HasVerificationVector() const;
bool IsMember(const uint256& proTxHash) const; bool IsMember(const uint256& proTxHash) const;
bool IsValidMember(const uint256& proTxHash) const; bool IsValidMember(const uint256& proTxHash) const;
int GetMemberIndex(const uint256& proTxHash) const; int GetMemberIndex(const uint256& proTxHash) const;
CBLSPublicKey GetPubKeyShare(size_t memberIdx) const; CBLSPublicKey GetPubKeyShare(size_t memberIdx) const;
const CBLSSecretKey& GetSkShare() const; CBLSSecretKey GetSkShare() const;
private: private:
void WriteContributions(CEvoDB& evoDb) const; void WriteContributions(CEvoDB& evoDb) const;

View File

@ -199,7 +199,7 @@ void CDKGSession::SendContributions(CDKGPendingMessages& pendingMessages)
logger.Batch("encrypted contributions. time=%d", t1.count()); logger.Batch("encrypted contributions. time=%d", t1.count());
qc.sig = activeMasternodeInfo.blsKeyOperator->Sign(qc.GetSignHash()); qc.sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(qc.GetSignHash()));
logger.Flush(); logger.Flush();
@ -324,7 +324,7 @@ void CDKGSession::ReceiveMessage(const CDKGContribution& qc, bool& retBan)
bool complain = false; bool complain = false;
CBLSSecretKey skContribution; CBLSSecretKey skContribution;
if (!qc.contributions->Decrypt(myIdx, *activeMasternodeInfo.blsKeyOperator, skContribution, PROTOCOL_VERSION)) { if (!qc.contributions->Decrypt(myIdx, WITH_LOCK(activeMasternodeInfoCs, return *activeMasternodeInfo.blsKeyOperator), skContribution, PROTOCOL_VERSION)) {
logger.Batch("contribution from %s could not be decrypted", member->dmn->proTxHash.ToString()); logger.Batch("contribution from %s could not be decrypted", member->dmn->proTxHash.ToString());
complain = true; complain = true;
} else if (member->idx != myIdx && ShouldSimulateError("complain-lie")) { } else if (member->idx != myIdx && ShouldSimulateError("complain-lie")) {
@ -466,10 +466,11 @@ void CDKGSession::VerifyConnectionAndMinProtoVersions() const
std::unordered_map<uint256, int, StaticSaltedHasher> protoMap; std::unordered_map<uint256, int, StaticSaltedHasher> protoMap;
g_connman->ForEachNode([&](const CNode* pnode) { g_connman->ForEachNode([&](const CNode* pnode) {
if (pnode->verifiedProRegTxHash.IsNull()) { auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (verifiedProRegTxHash.IsNull()) {
return; return;
} }
protoMap.emplace(pnode->verifiedProRegTxHash, pnode->nVersion); protoMap.emplace(verifiedProRegTxHash, pnode->nVersion);
}); });
bool fShouldAllMembersBeConnected = CLLMQUtils::IsAllMembersConnectedEnabled(params.type); bool fShouldAllMembersBeConnected = CLLMQUtils::IsAllMembersConnectedEnabled(params.type);
@ -525,7 +526,7 @@ void CDKGSession::SendComplaint(CDKGPendingMessages& pendingMessages)
logger.Batch("sending complaint. badCount=%d, complaintCount=%d", badCount, complaintCount); logger.Batch("sending complaint. badCount=%d, complaintCount=%d", badCount, complaintCount);
qc.sig = activeMasternodeInfo.blsKeyOperator->Sign(qc.GetSignHash()); qc.sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(qc.GetSignHash()));
logger.Flush(); logger.Flush();
@ -725,7 +726,7 @@ void CDKGSession::SendJustification(CDKGPendingMessages& pendingMessages, const
return; return;
} }
qj.sig = activeMasternodeInfo.blsKeyOperator->Sign(qj.GetSignHash()); qj.sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(qj.GetSignHash()));
logger.Flush(); logger.Flush();
@ -1027,7 +1028,7 @@ void CDKGSession::SendCommitment(CDKGPendingMessages& pendingMessages)
(*commitmentHash.begin())++; (*commitmentHash.begin())++;
} }
qc.sig = activeMasternodeInfo.blsKeyOperator->Sign(commitmentHash); qc.sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(commitmentHash));
qc.quorumSig = skShare.Sign(commitmentHash); qc.quorumSig = skShare.Sign(commitmentHash);
if (lieType == 3) { if (lieType == 3) {
@ -1334,9 +1335,10 @@ void CDKGSession::RelayInvToParticipants(const CInv& inv) const
LOCK(invCs); LOCK(invCs);
g_connman->ForEachNode([&](CNode* pnode) { g_connman->ForEachNode([&](CNode* pnode) {
bool relay = false; bool relay = false;
auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (pnode->qwatch) { if (pnode->qwatch) {
relay = true; relay = true;
} else if (!pnode->verifiedProRegTxHash.IsNull() && relayMembers.count(pnode->verifiedProRegTxHash)) { } else if (!verifiedProRegTxHash.IsNull() && relayMembers.count(verifiedProRegTxHash)) {
relay = true; relay = true;
} }
if (relay) { if (relay) {

View File

@ -166,7 +166,7 @@ bool CDKGSessionHandler::InitNewQuorum(const CBlockIndex* pindexQuorum)
auto mns = CLLMQUtils::GetAllQuorumMembers(params.type, pindexQuorum); auto mns = CLLMQUtils::GetAllQuorumMembers(params.type, pindexQuorum);
if (!curSession->Init(pindexQuorum, mns, activeMasternodeInfo.proTxHash)) { if (!curSession->Init(pindexQuorum, mns, WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash))) {
LogPrintf("CDKGSessionManager::%s -- quorum initialization failed for %s\n", __func__, curSession->params.name); LogPrintf("CDKGSessionManager::%s -- quorum initialization failed for %s\n", __func__, curSession->params.name);
return false; return false;
} }

View File

@ -784,7 +784,7 @@ void CSigningManager::UnregisterRecoveredSigsListener(CRecoveredSigsListener* l)
bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash, const uint256& quorumHash, bool allowReSign) bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash, const uint256& quorumHash, bool allowReSign)
{ {
if (!fMasternodeMode || activeMasternodeInfo.proTxHash.IsNull()) { if (!fMasternodeMode || WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash.IsNull())) {
return false; return false;
} }
@ -805,7 +805,7 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint
return false; return false;
} }
if (!quorum->IsValidMember(activeMasternodeInfo.proTxHash)) { if (!WITH_LOCK(activeMasternodeInfoCs, return quorum->IsValidMember(activeMasternodeInfo.proTxHash))) {
return false; return false;
} }

View File

@ -234,7 +234,7 @@ void CSigSharesManager::InterruptWorkerThread()
void CSigSharesManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv) void CSigSharesManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv)
{ {
// non-masternodes are not interested in sigshares // non-masternodes are not interested in sigshares
if (!fMasternodeMode || activeMasternodeInfo.proTxHash.IsNull()) { if (!fMasternodeMode || WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash.IsNull())) {
return; return;
} }
@ -372,7 +372,7 @@ bool CSigSharesManager::ProcessMessageSigSharesInv(CNode* pfrom, const CSigShare
LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- signHash=%s, inv={%s}, node=%d\n", __func__, LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- signHash=%s, inv={%s}, node=%d\n", __func__,
sessionInfo.signHash.ToString(), inv.ToString(), pfrom->GetId()); sessionInfo.signHash.ToString(), inv.ToString(), pfrom->GetId());
if (sessionInfo.quorum->quorumVvec == nullptr) { if (!sessionInfo.quorum->HasVerificationVector()) {
// TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG
LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, not requesting sig shares. node=%d\n", __func__, LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, not requesting sig shares. node=%d\n", __func__,
sessionInfo.quorumHash.ToString(), pfrom->GetId()); sessionInfo.quorumHash.ToString(), pfrom->GetId());
@ -485,11 +485,11 @@ void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& s
// quorum is too old // quorum is too old
return; return;
} }
if (!quorum->IsMember(activeMasternodeInfo.proTxHash)) { if (!quorum->IsMember(WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash))) {
// we're not a member so we can't verify it (we actually shouldn't have received it) // we're not a member so we can't verify it (we actually shouldn't have received it)
return; return;
} }
if (quorum->quorumVvec == nullptr) { if (!quorum->HasVerificationVector()) {
// TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG
LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible. node=%d\n", __func__, LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible. node=%d\n", __func__,
quorum->qc->quorumHash.ToString(), fromId); quorum->qc->quorumHash.ToString(), fromId);
@ -534,11 +534,11 @@ bool CSigSharesManager::PreVerifyBatchedSigShares(const CSigSharesNodeState::Ses
// quorum is too old // quorum is too old
return false; return false;
} }
if (!session.quorum->IsMember(activeMasternodeInfo.proTxHash)) { if (!session.quorum->IsMember(WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash))) {
// we're not a member so we can't verify it (we actually shouldn't have received it) // we're not a member so we can't verify it (we actually shouldn't have received it)
return false; return false;
} }
if (session.quorum->quorumVvec == nullptr) { if (!session.quorum->HasVerificationVector()) {
// TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG
LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible.\n", __func__, LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible.\n", __func__,
session.quorumHash.ToString()); session.quorumHash.ToString());
@ -730,7 +730,7 @@ void CSigSharesManager::ProcessSigShare(const CSigShare& sigShare, CConnman& con
// prepare node set for direct-push in case this is our sig share // prepare node set for direct-push in case this is our sig share
std::set<NodeId> quorumNodes; std::set<NodeId> quorumNodes;
if (!CLLMQUtils::IsAllMembersConnectedEnabled(llmqType) && sigShare.quorumMember == quorum->GetMemberIndex(activeMasternodeInfo.proTxHash)) { if (!CLLMQUtils::IsAllMembersConnectedEnabled(llmqType) && sigShare.quorumMember == quorum->GetMemberIndex(WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash))) {
quorumNodes = connman.GetMasternodeQuorumNodes(sigShare.llmqType, sigShare.quorumHash); quorumNodes = connman.GetMasternodeQuorumNodes(sigShare.llmqType, sigShare.quorumHash);
} }
@ -1018,10 +1018,11 @@ void CSigSharesManager::CollectSigSharesToSendConcentrated(std::unordered_map<No
std::unordered_map<uint256, CNode*> proTxToNode; std::unordered_map<uint256, CNode*> proTxToNode;
for (const auto& pnode : vNodes) { for (const auto& pnode : vNodes) {
if (pnode->verifiedProRegTxHash.IsNull()) { auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (verifiedProRegTxHash.IsNull()) {
continue; continue;
} }
proTxToNode.emplace(pnode->verifiedProRegTxHash, pnode); proTxToNode.emplace(verifiedProRegTxHash, pnode);
} }
auto curTime = GetTime<std::chrono::milliseconds>().count(); auto curTime = GetTime<std::chrono::milliseconds>().count();
@ -1567,8 +1568,9 @@ void CSigSharesManager::SignPendingSigShares()
CSigShare CSigSharesManager::CreateSigShare(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash) const CSigShare CSigSharesManager::CreateSigShare(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash) const
{ {
cxxtimer::Timer t(true); cxxtimer::Timer t(true);
auto activeMasterNodeProTxHash = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash);
if (!quorum->IsValidMember(activeMasternodeInfo.proTxHash)) { if (!quorum->IsValidMember(activeMasterNodeProTxHash)) {
return {}; return {};
} }
@ -1578,7 +1580,7 @@ CSigShare CSigSharesManager::CreateSigShare(const CQuorumCPtr& quorum, const uin
return {}; return {};
} }
int memberIdx = quorum->GetMemberIndex(activeMasternodeInfo.proTxHash); int memberIdx = quorum->GetMemberIndex(activeMasterNodeProTxHash);
if (memberIdx == -1) { if (memberIdx == -1) {
// this should really not happen (IsValidMember gave true) // this should really not happen (IsValidMember gave true)
return {}; return {};

View File

@ -15,7 +15,8 @@
#include <bls/bls.h> #include <bls/bls.h>
// Keep track of the active Masternode // Keep track of the active Masternode
CActiveMasternodeInfo activeMasternodeInfo; CCriticalSection activeMasternodeInfoCs;
CActiveMasternodeInfo activeMasternodeInfo GUARDED_BY(activeMasternodeInfoCs);
CActiveMasternodeManager* activeMasternodeManager; CActiveMasternodeManager* activeMasternodeManager;
std::string CActiveMasternodeManager::GetStateString() const std::string CActiveMasternodeManager::GetStateString() const
@ -64,7 +65,7 @@ std::string CActiveMasternodeManager::GetStatus() const
void CActiveMasternodeManager::Init(const CBlockIndex* pindex) void CActiveMasternodeManager::Init(const CBlockIndex* pindex)
{ {
LOCK(cs_main); LOCK2(cs_main, activeMasternodeInfoCs);
if (!fMasternodeMode) return; if (!fMasternodeMode) return;
@ -136,7 +137,7 @@ void CActiveMasternodeManager::Init(const CBlockIndex* pindex)
void CActiveMasternodeManager::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) void CActiveMasternodeManager::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload)
{ {
LOCK(cs_main); LOCK2(cs_main, activeMasternodeInfoCs);
if (!fMasternodeMode) return; if (!fMasternodeMode) return;
@ -201,10 +202,11 @@ bool CActiveMasternodeManager::GetLocalAddress(CService& addrRet)
if (!fFoundLocal) { if (!fFoundLocal) {
bool empty = true; bool empty = true;
// If we have some peers, let's try to find our local address from one of them // If we have some peers, let's try to find our local address from one of them
g_connman->ForEachNodeContinueIf(CConnman::AllNodes, [&fFoundLocal, &empty](CNode* pnode) { auto service = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.service);
g_connman->ForEachNodeContinueIf(CConnman::AllNodes, [&](CNode* pnode) {
empty = false; empty = false;
if (pnode->addr.IsIPv4()) if (pnode->addr.IsIPv4())
fFoundLocal = GetLocal(activeMasternodeInfo.service, &pnode->addr) && IsValidNetAddr(activeMasternodeInfo.service); fFoundLocal = GetLocal(service, &pnode->addr) && IsValidNetAddr(service);
return !fFoundLocal; return !fFoundLocal;
}); });
// nothing and no live connections, can't do anything for now // nothing and no live connections, can't do anything for now

View File

@ -16,6 +16,7 @@ struct CActiveMasternodeInfo;
class CActiveMasternodeManager; class CActiveMasternodeManager;
extern CActiveMasternodeInfo activeMasternodeInfo; extern CActiveMasternodeInfo activeMasternodeInfo;
extern CCriticalSection activeMasternodeInfoCs;
extern CActiveMasternodeManager* activeMasternodeManager; extern CActiveMasternodeManager* activeMasternodeManager;
struct CActiveMasternodeInfo { struct CActiveMasternodeInfo {

View File

@ -925,7 +925,7 @@ bool CConnman::AttemptToEvictConnection()
} }
// if MNAUTH was valid, the node is always protected (and at the same time not accounted when // if MNAUTH was valid, the node is always protected (and at the same time not accounted when
// checking incoming connection limits) // checking incoming connection limits)
if (!node->verifiedProRegTxHash.IsNull()) { if (!node->GetVerifiedProRegTxHash().IsNull()) {
isProtected = true; isProtected = true;
} }
if (isProtected) { if (isProtected) {
@ -1036,7 +1036,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
for (const CNode* pnode : vNodes) { for (const CNode* pnode : vNodes) {
if (pnode->fInbound) { if (pnode->fInbound) {
nInbound++; nInbound++;
if (!pnode->verifiedProRegTxHash.IsNull()) { if (!pnode->GetVerifiedProRegTxHash().IsNull()) {
nVerifiedInboundMasternodes++; nVerifiedInboundMasternodes++;
} }
} }
@ -2251,8 +2251,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
for (CNode* pnode : vNodes) { for (CNode* pnode : vNodes) {
if (!pnode->verifiedProRegTxHash.IsNull()) { auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
setConnectedMasternodes.emplace(pnode->verifiedProRegTxHash); if (!verifiedProRegTxHash.IsNull()) {
setConnectedMasternodes.emplace(verifiedProRegTxHash);
} }
} }
} }
@ -2475,9 +2476,10 @@ void CConnman::ThreadOpenMasternodeConnections()
std::set<CService> connectedNodes; std::set<CService> connectedNodes;
std::map<uint256, bool> connectedProRegTxHashes; std::map<uint256, bool> connectedProRegTxHashes;
ForEachNode([&](const CNode* pnode) { ForEachNode([&](const CNode* pnode) {
auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
connectedNodes.emplace(pnode->addr); connectedNodes.emplace(pnode->addr);
if (!pnode->verifiedProRegTxHash.IsNull()) { if (!verifiedProRegTxHash.IsNull()) {
connectedProRegTxHashes.emplace(pnode->verifiedProRegTxHash, pnode->fInbound); connectedProRegTxHashes.emplace(verifiedProRegTxHash, pnode->fInbound);
} }
}); });
@ -3344,7 +3346,8 @@ void CConnman::SetMasternodeQuorumRelayMembers(Consensus::LLMQType llmqType, con
// Update existing connections // Update existing connections
ForEachNode([&](CNode* pnode) { ForEachNode([&](CNode* pnode) {
if (!pnode->verifiedProRegTxHash.IsNull() && !pnode->m_masternode_iqr_connection && IsMasternodeQuorumRelayMember(pnode->verifiedProRegTxHash)) { auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (!verifiedProRegTxHash.IsNull() && !pnode->m_masternode_iqr_connection && IsMasternodeQuorumRelayMember(verifiedProRegTxHash)) {
// Tell our peer that we're interested in plain LLMQ recovered signatures. // Tell our peer that we're interested in plain LLMQ recovered signatures.
// Otherwise the peer would only announce/send messages resulting from QRECSIG, // Otherwise the peer would only announce/send messages resulting from QRECSIG,
// e.g. InstantSend locks or ChainLocks. SPV and regular full nodes should not send // e.g. InstantSend locks or ChainLocks. SPV and regular full nodes should not send
@ -3389,7 +3392,8 @@ std::set<NodeId> CConnman::GetMasternodeQuorumNodes(Consensus::LLMQType llmqType
if (pnode->fDisconnect) { if (pnode->fDisconnect) {
continue; continue;
} }
if (!pnode->qwatch && (pnode->verifiedProRegTxHash.IsNull() || !proRegTxHashes.count(pnode->verifiedProRegTxHash))) { auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (!pnode->qwatch && (verifiedProRegTxHash.IsNull() || !proRegTxHashes.count(verifiedProRegTxHash))) {
continue; continue;
} }
nodes.emplace(pnode->GetId()); nodes.emplace(pnode->GetId());
@ -3409,7 +3413,7 @@ bool CConnman::IsMasternodeQuorumNode(const CNode* pnode)
// Let's see if this is an outgoing connection to an address that is known to be a masternode // Let's see if this is an outgoing connection to an address that is known to be a masternode
// We however only need to know this if the node did not authenticate itself as a MN yet // We however only need to know this if the node did not authenticate itself as a MN yet
uint256 assumedProTxHash; uint256 assumedProTxHash;
if (pnode->verifiedProRegTxHash.IsNull() && !pnode->fInbound) { if (pnode->GetVerifiedProRegTxHash().IsNull() && !pnode->fInbound) {
auto mnList = deterministicMNManager->GetListAtChainTip(); auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetMNByService(pnode->addr); auto dmn = mnList.GetMNByService(pnode->addr);
if (dmn == nullptr) { if (dmn == nullptr) {
@ -3421,8 +3425,8 @@ bool CConnman::IsMasternodeQuorumNode(const CNode* pnode)
LOCK(cs_vPendingMasternodes); LOCK(cs_vPendingMasternodes);
for (const auto& p : masternodeQuorumNodes) { for (const auto& p : masternodeQuorumNodes) {
if (!pnode->verifiedProRegTxHash.IsNull()) { if (!pnode->GetVerifiedProRegTxHash().IsNull()) {
if (p.second.count(pnode->verifiedProRegTxHash)) { if (p.second.count(pnode->GetVerifiedProRegTxHash())) {
return true; return true;
} }
} else if (!assumedProTxHash.IsNull()) { } else if (!assumedProTxHash.IsNull()) {

View File

@ -905,11 +905,11 @@ public:
bool fRelayTxes; //protected by cs_filter bool fRelayTxes; //protected by cs_filter
bool fSentAddr; bool fSentAddr;
// If 'true' this node will be disconnected on CMasternodeMan::ProcessMasternodeConnections() // If 'true' this node will be disconnected on CMasternodeMan::ProcessMasternodeConnections()
bool m_masternode_connection; std::atomic<bool> m_masternode_connection;
// If 'true' this node will be disconnected after MNAUTH // If 'true' this node will be disconnected after MNAUTH
bool m_masternode_probe_connection; std::atomic<bool> m_masternode_probe_connection;
// If 'true', we identified it as an intra-quorum relay connection // If 'true', we identified it as an intra-quorum relay connection
bool m_masternode_iqr_connection{false}; std::atomic<bool> m_masternode_iqr_connection{false};
CSemaphoreGrant grantOutbound; CSemaphoreGrant grantOutbound;
CCriticalSection cs_filter; CCriticalSection cs_filter;
std::unique_ptr<CBloomFilter> pfilter PT_GUARDED_BY(cs_filter){nullptr}; std::unique_ptr<CBloomFilter> pfilter PT_GUARDED_BY(cs_filter){nullptr};
@ -980,13 +980,6 @@ public:
// If true, we will send him CoinJoin queue messages // If true, we will send him CoinJoin queue messages
std::atomic<bool> fSendDSQueue{false}; std::atomic<bool> fSendDSQueue{false};
// Challenge sent in VERSION to be answered with MNAUTH (only happens between MNs)
mutable CCriticalSection cs_mnauth;
uint256 sentMNAuthChallenge;
uint256 receivedMNAuthChallenge;
uint256 verifiedProRegTxHash;
uint256 verifiedPubKeyHash;
// If true, we will announce/send him plain recovered sigs (usually true for full nodes) // If true, we will announce/send him plain recovered sigs (usually true for full nodes)
std::atomic<bool> fSendRecSigs{false}; std::atomic<bool> fSendRecSigs{false};
// If true, we will send him all quorum related messages, even if he is not a member of our quorums // If true, we will send him all quorum related messages, even if he is not a member of our quorums
@ -1015,6 +1008,14 @@ private:
// Our address, as reported by the peer // Our address, as reported by the peer
CService addrLocal GUARDED_BY(cs_addrLocal); CService addrLocal GUARDED_BY(cs_addrLocal);
mutable CCriticalSection cs_addrLocal; mutable CCriticalSection cs_addrLocal;
// Challenge sent in VERSION to be answered with MNAUTH (only happens between MNs)
mutable CCriticalSection cs_mnauth;
uint256 sentMNAuthChallenge GUARDED_BY(cs_mnauth);
uint256 receivedMNAuthChallenge GUARDED_BY(cs_mnauth);
uint256 verifiedProRegTxHash GUARDED_BY(cs_mnauth);
uint256 verifiedPubKeyHash GUARDED_BY(cs_mnauth);
public: public:
NodeId GetId() const { NodeId GetId() const {
@ -1148,6 +1149,46 @@ public:
std::string GetLogString() const; std::string GetLogString() const;
bool CanRelay() const { return !m_masternode_connection || m_masternode_iqr_connection; } bool CanRelay() const { return !m_masternode_connection || m_masternode_iqr_connection; }
uint256 GetSentMNAuthChallenge() const {
LOCK(cs_mnauth);
return sentMNAuthChallenge;
}
uint256 GetReceivedMNAuthChallenge() const {
LOCK(cs_mnauth);
return receivedMNAuthChallenge;
}
uint256 GetVerifiedProRegTxHash() const {
LOCK(cs_mnauth);
return verifiedProRegTxHash;
}
uint256 GetVerifiedPubKeyHash() const {
LOCK(cs_mnauth);
return verifiedPubKeyHash;
}
void SetSentMNAuthChallenge(const uint256& newSentMNAuthChallenge) {
LOCK(cs_mnauth);
sentMNAuthChallenge = newSentMNAuthChallenge;
}
void SetReceivedMNAuthChallenge(const uint256& newReceivedMNAuthChallenge) {
LOCK(cs_mnauth);
receivedMNAuthChallenge = newReceivedMNAuthChallenge;
}
void SetVerifiedProRegTxHash(const uint256& newVerifiedProRegTxHash) {
LOCK(cs_mnauth);
verifiedProRegTxHash = newVerifiedProRegTxHash;
}
void SetVerifiedPubKeyHash(const uint256& newVerifiedPubKeyHash) {
LOCK(cs_mnauth);
verifiedPubKeyHash = newVerifiedPubKeyHash;
}
}; };
class CExplicitNetCleanup class CExplicitNetCleanup

View File

@ -438,10 +438,7 @@ static void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime)
uint256 mnauthChallenge; uint256 mnauthChallenge;
GetRandBytes(mnauthChallenge.begin(), mnauthChallenge.size()); GetRandBytes(mnauthChallenge.begin(), mnauthChallenge.size());
{ pnode->SetSentMNAuthChallenge(mnauthChallenge);
LOCK(pnode->cs_mnauth);
pnode->sentMNAuthChallenge = mnauthChallenge;
}
int nProtocolVersion = PROTOCOL_VERSION; int nProtocolVersion = PROTOCOL_VERSION;
if (params.NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) { if (params.NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) {
@ -449,7 +446,7 @@ static void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime)
} }
connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, nProtocolVersion, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe, connman->PushMessage(pnode, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::VERSION, nProtocolVersion, (uint64_t)nLocalNodeServices, nTime, addrYou, addrMe,
nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes, mnauthChallenge, pnode->m_masternode_connection)); nonce, strSubVersion, nNodeStartingHeight, ::g_relay_txes, mnauthChallenge, pnode->m_masternode_connection.load()));
if (fLogIPs) { if (fLogIPs) {
LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", nProtocolVersion, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid); LogPrint(BCLog::NET, "send version message: version %d, blocks=%d, us=%s, them=%s, peer=%d\n", nProtocolVersion, nNodeStartingHeight, addrMe.ToString(), addrYou.ToString(), nodeid);
@ -2222,8 +2219,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
if (!vRecv.empty()) if (!vRecv.empty())
vRecv >> fRelay; vRecv >> fRelay;
if (!vRecv.empty()) { if (!vRecv.empty()) {
LOCK(pfrom->cs_mnauth); uint256 receivedMNAuthChallenge;
vRecv >> pfrom->receivedMNAuthChallenge; vRecv >> receivedMNAuthChallenge;
pfrom->SetReceivedMNAuthChallenge(receivedMNAuthChallenge);
} }
if (!vRecv.empty()) { if (!vRecv.empty()) {
bool fOtherMasternode = false; bool fOtherMasternode = false;
@ -4283,7 +4281,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
} else { } else {
// Use half the delay for regular outbound peers, as there is less privacy concern for them. // Use half the delay for regular outbound peers, as there is less privacy concern for them.
// and quarter the delay for Masternode outbound peers, as there is even less privacy concern in this case. // and quarter the delay for Masternode outbound peers, as there is even less privacy concern in this case.
pto->nNextInvSend = PoissonNextSend(current_time, std::chrono::seconds{INVENTORY_BROADCAST_INTERVAL >> 1 >> !pto->verifiedProRegTxHash.IsNull()}); pto->nNextInvSend = PoissonNextSend(current_time, std::chrono::seconds{INVENTORY_BROADCAST_INTERVAL >> 1 >> !pto->GetVerifiedProRegTxHash().IsNull()});
} }
} }

View File

@ -310,11 +310,11 @@ static UniValue gobject_submit(const JSONRPCRequest& request)
} }
auto mnList = deterministicMNManager->GetListAtChainTip(); auto mnList = deterministicMNManager->GetListAtChainTip();
bool fMnFound = mnList.HasValidMNByCollateral(activeMasternodeInfo.outpoint); bool fMnFound = WITH_LOCK(activeMasternodeInfoCs, return mnList.HasValidMNByCollateral(activeMasternodeInfo.outpoint));
LogPrint(BCLog::GOBJECT, "gobject_submit -- pubKeyOperator = %s, outpoint = %s, params.size() = %lld, fMnFound = %d\n", LogPrint(BCLog::GOBJECT, "gobject_submit -- pubKeyOperator = %s, outpoint = %s, params.size() = %lld, fMnFound = %d\n",
(activeMasternodeInfo.blsPubKeyOperator ? activeMasternodeInfo.blsPubKeyOperator->ToString() : "N/A"), (WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsPubKeyOperator ? activeMasternodeInfo.blsPubKeyOperator->ToString() : "N/A")),
activeMasternodeInfo.outpoint.ToStringShort(), request.params.size(), fMnFound); WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.outpoint.ToStringShort()), request.params.size(), fMnFound);
// ASSEMBLE NEW GOVERNANCE OBJECT FROM USER PARAMETERS // ASSEMBLE NEW GOVERNANCE OBJECT FROM USER PARAMETERS
@ -351,6 +351,7 @@ static UniValue gobject_submit(const JSONRPCRequest& request)
// Attempt to sign triggers if we are a MN // Attempt to sign triggers if we are a MN
if (govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) { if (govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) {
if (fMnFound) { if (fMnFound) {
LOCK(activeMasternodeInfoCs);
govobj.SetMasternodeOutpoint(activeMasternodeInfo.outpoint); govobj.SetMasternodeOutpoint(activeMasternodeInfo.outpoint);
govobj.Sign(*activeMasternodeInfo.blsKeyOperator); govobj.Sign(*activeMasternodeInfo.blsKeyOperator);
} else { } else {
@ -450,7 +451,7 @@ static UniValue gobject_vote_conf(const JSONRPCRequest& request)
UniValue statusObj(UniValue::VOBJ); UniValue statusObj(UniValue::VOBJ);
UniValue returnObj(UniValue::VOBJ); UniValue returnObj(UniValue::VOBJ);
auto dmn = deterministicMNManager->GetListAtChainTip().GetValidMNByCollateral(activeMasternodeInfo.outpoint); auto dmn = WITH_LOCK(activeMasternodeInfoCs, return deterministicMNManager->GetListAtChainTip().GetValidMNByCollateral(activeMasternodeInfo.outpoint));
if (!dmn) { if (!dmn) {
nFailed++; nFailed++;
@ -468,8 +469,12 @@ static UniValue gobject_vote_conf(const JSONRPCRequest& request)
if (govObjType == GOVERNANCE_OBJECT_PROPOSAL && eVoteSignal == VOTE_SIGNAL_FUNDING) { if (govObjType == GOVERNANCE_OBJECT_PROPOSAL && eVoteSignal == VOTE_SIGNAL_FUNDING) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Can't use vote-conf for proposals"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Can't use vote-conf for proposals");
} }
if (activeMasternodeInfo.blsKeyOperator) {
signSuccess = vote.Sign(*activeMasternodeInfo.blsKeyOperator); {
LOCK(activeMasternodeInfoCs);
if (activeMasternodeInfo.blsKeyOperator) {
signSuccess = vote.Sign(*activeMasternodeInfo.blsKeyOperator);
}
} }
if (!signSuccess) { if (!signSuccess) {

View File

@ -233,11 +233,15 @@ static UniValue masternode_status(const JSONRPCRequest& request)
UniValue mnObj(UniValue::VOBJ); UniValue mnObj(UniValue::VOBJ);
// keep compatibility with legacy status for now (might get deprecated/removed later) CDeterministicMNCPtr dmn;
mnObj.pushKV("outpoint", activeMasternodeInfo.outpoint.ToStringShort()); {
mnObj.pushKV("service", activeMasternodeInfo.service.ToString()); LOCK(activeMasternodeInfoCs);
auto dmn = deterministicMNManager->GetListAtChainTip().GetMN(activeMasternodeInfo.proTxHash); // keep compatibility with legacy status for now (might get deprecated/removed later)
mnObj.pushKV("outpoint", activeMasternodeInfo.outpoint.ToStringShort());
mnObj.pushKV("service", activeMasternodeInfo.service.ToString());
dmn = deterministicMNManager->GetListAtChainTip().GetMN(activeMasternodeInfo.proTxHash);
}
if (dmn) { if (dmn) {
mnObj.pushKV("proTxHash", dmn->proTxHash.ToString()); mnObj.pushKV("proTxHash", dmn->proTxHash.ToString());
mnObj.pushKV("collateralHash", dmn->collateralOutpoint.hash.ToString()); mnObj.pushKV("collateralHash", dmn->collateralOutpoint.hash.ToString());

View File

@ -447,9 +447,8 @@ static UniValue mnauth(const JSONRPCRequest& request)
} }
bool fSuccess = g_connman->ForNode(nodeId, CConnman::AllNodes, [&](CNode* pNode){ bool fSuccess = g_connman->ForNode(nodeId, CConnman::AllNodes, [&](CNode* pNode){
LOCK(pNode->cs_mnauth); pNode->SetVerifiedProRegTxHash(proTxHash);
pNode->verifiedProRegTxHash = proTxHash; pNode->SetVerifiedPubKeyHash(publicKey.GetHash());
pNode->verifiedPubKeyHash = publicKey.GetHash();
return true; return true;
}); });

View File

@ -191,6 +191,7 @@ static UniValue quorum_dkgstatus(const JSONRPCRequest& request)
} }
int tipHeight = pindexTip->nHeight; int tipHeight = pindexTip->nHeight;
auto proTxHash = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash);
UniValue minableCommitments(UniValue::VOBJ); UniValue minableCommitments(UniValue::VOBJ);
UniValue quorumConnections(UniValue::VOBJ); UniValue quorumConnections(UniValue::VOBJ);
for (const auto& type : llmq::CLLMQUtils::GetEnabledQuorumTypes(pindexTip)) { for (const auto& type : llmq::CLLMQUtils::GetEnabledQuorumTypes(pindexTip)) {
@ -202,12 +203,13 @@ static UniValue quorum_dkgstatus(const JSONRPCRequest& request)
LOCK(cs_main); LOCK(cs_main);
pindexQuorum = chainActive[tipHeight - (tipHeight % llmq_params.dkgInterval)]; pindexQuorum = chainActive[tipHeight - (tipHeight % llmq_params.dkgInterval)];
} }
auto allConnections = llmq::CLLMQUtils::GetQuorumConnections(llmq_params.type, pindexQuorum, activeMasternodeInfo.proTxHash, false); auto allConnections = llmq::CLLMQUtils::GetQuorumConnections(llmq_params.type, pindexQuorum, proTxHash, false);
auto outboundConnections = llmq::CLLMQUtils::GetQuorumConnections(llmq_params.type, pindexQuorum, activeMasternodeInfo.proTxHash, true); auto outboundConnections = llmq::CLLMQUtils::GetQuorumConnections(llmq_params.type, pindexQuorum, proTxHash, true);
std::map<uint256, CAddress> foundConnections; std::map<uint256, CAddress> foundConnections;
g_connman->ForEachNode([&](const CNode* pnode) { g_connman->ForEachNode([&](const CNode* pnode) {
if (!pnode->verifiedProRegTxHash.IsNull() && allConnections.count(pnode->verifiedProRegTxHash)) { auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
foundConnections.emplace(pnode->verifiedProRegTxHash, pnode->addr); if (!verifiedProRegTxHash.IsNull() && allConnections.count(verifiedProRegTxHash)) {
foundConnections.emplace(verifiedProRegTxHash, pnode->addr);
} }
}); });
UniValue arr(UniValue::VARR); UniValue arr(UniValue::VARR);

View File

@ -25,7 +25,7 @@
#include <unordered_map> #include <unordered_map>
static CCriticalSection cs_rpcWarmup; static CCriticalSection cs_rpcWarmup;
static bool fRPCRunning = false; static std::atomic<bool> fRPCRunning{false};
static bool fRPCInWarmup GUARDED_BY(cs_rpcWarmup) = true; static bool fRPCInWarmup GUARDED_BY(cs_rpcWarmup) = true;
static std::string rpcWarmupStatus GUARDED_BY(cs_rpcWarmup) = "RPC server started"; static std::string rpcWarmupStatus GUARDED_BY(cs_rpcWarmup) = "RPC server started";
/* Timer-creating functions */ /* Timer-creating functions */

View File

@ -4377,11 +4377,14 @@ bool CWallet::ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRe
void CWallet::KeepKey(int64_t nIndex) void CWallet::KeepKey(int64_t nIndex)
{ {
// Remove from key pool // Remove from key pool
WalletBatch batch(*database); {
if (batch.ErasePool(nIndex)) LOCK(cs_wallet);
--nKeysLeftSinceAutoBackup; WalletBatch batch(*database);
if (!nWalletBackups) if (batch.ErasePool(nIndex))
nKeysLeftSinceAutoBackup = 0; --nKeysLeftSinceAutoBackup;
if (!nWalletBackups)
nKeysLeftSinceAutoBackup = 0;
}
WalletLogPrintf("keypool keep %d\n", nIndex); WalletLogPrintf("keypool keep %d\n", nIndex);
} }