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 */
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetValidMNByCollateral(activeMasternodeInfo.outpoint);
auto dmn = WITH_LOCK(activeMasternodeInfoCs, return mnList.GetValidMNByCollateral(activeMasternodeInfo.outpoint));
if (!dmn) {
PushStatus(pfrom, STATUS_REJECTED, ERR_MN_LIST, connman);
return;
@ -68,7 +68,7 @@ void CCoinJoinServer::ProcessMessage(CNode* pfrom, const std::string& strCommand
if (!lockRecv) return;
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
LogPrint(BCLog::COINJOIN, "DSACCEPT -- last dsq is still in queue, refuse to mix\n");
PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman);
@ -334,7 +334,7 @@ void CCoinJoinServer::CommitFinalTransaction(CConnman& connman)
// create and sign masternode dstx transaction
if (!CCoinJoin::GetDSTX(hashTx)) {
CCoinJoinBroadcastTx dstxNew(finalTransaction, activeMasternodeInfo.outpoint, GetAdjustedTime());
CCoinJoinBroadcastTx dstxNew(finalTransaction, WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.outpoint), GetAdjustedTime());
dstxNew.Sign();
CCoinJoin::AddDSTX(dstxNew);
}
@ -501,7 +501,7 @@ void CCoinJoinServer::CheckForCompleteQueue(CConnman& connman)
if (nState == POOL_STATE_QUEUE && IsSessionReady()) {
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 */
"with %d participants\n", dsq.ToString(), vecSessionCollaterals.size());
dsq.Sign();
@ -708,7 +708,7 @@ bool CCoinJoinServer::CreateNewSession(const CCoinJoinAccept& dsa, PoolMessage&
if (!fUnitTest) {
//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());
dsq.Sign();
dsq.Relay(connman);

View File

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

View File

@ -18,31 +18,30 @@
void CMNAuth::PushMNAUTH(CNode* pnode, CConnman& connman)
{
LOCK(activeMasternodeInfoCs);
if (!fMasternodeMode || activeMasternodeInfo.proTxHash.IsNull()) {
return;
}
uint256 signHash;
{
LOCK(pnode->cs_mnauth);
if (pnode->receivedMNAuthChallenge.IsNull()) {
return;
}
// 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:
// node1 <- Eve -> node2
// It does not protect against:
// node1 -> Eve -> node2
// This is ok as we only use MNAUTH as a DoS protection and not for sensitive stuff
int nOurNodeVersion{PROTOCOL_VERSION};
if (Params().NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) {
nOurNodeVersion = gArgs.GetArg("-pushversion", PROTOCOL_VERSION);
}
if (pnode->nVersion < MNAUTH_NODE_VER_VERSION || nOurNodeVersion < MNAUTH_NODE_VER_VERSION) {
signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, pnode->receivedMNAuthChallenge, pnode->fInbound));
} else {
signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, pnode->receivedMNAuthChallenge, pnode->fInbound, nOurNodeVersion));
}
auto receivedMNAuthChallenge = pnode->GetReceivedMNAuthChallenge();
if (receivedMNAuthChallenge.IsNull()) {
return;
}
// 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:
// node1 <- Eve -> node2
// It does not protect against:
// node1 -> Eve -> node2
// This is ok as we only use MNAUTH as a DoS protection and not for sensitive stuff
int nOurNodeVersion{PROTOCOL_VERSION};
if (Params().NetworkIDString() != CBaseChainParams::MAIN && gArgs.IsArgSet("-pushversion")) {
nOurNodeVersion = gArgs.GetArg("-pushversion", PROTOCOL_VERSION);
}
if (pnode->nVersion < MNAUTH_NODE_VER_VERSION || nOurNodeVersion < MNAUTH_NODE_VER_VERSION) {
signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, receivedMNAuthChallenge, pnode->fInbound));
} else {
signHash = ::SerializeHash(std::make_tuple(*activeMasternodeInfo.blsPubKeyOperator, receivedMNAuthChallenge, pnode->fInbound, nOurNodeVersion));
}
CMNAuth mnauth;
@ -66,11 +65,7 @@ void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataS
vRecv >> mnauth;
// only one MNAUTH allowed
bool fAlreadyHaveMNAUTH = false;
{
LOCK(pnode->cs_mnauth);
fAlreadyHaveMNAUTH = !pnode->verifiedProRegTxHash.IsNull();
}
bool fAlreadyHaveMNAUTH = !pnode->GetVerifiedProRegTxHash().IsNull();
if (fAlreadyHaveMNAUTH) {
LOCK(cs_main);
Misbehaving(pnode->GetId(), 100, "duplicate mnauth");
@ -108,20 +103,17 @@ void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataS
}
uint256 signHash;
{
LOCK(pnode->cs_mnauth);
int nOurNodeVersion{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());
int nOurNodeVersion{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->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)) {
LOCK(cs_main);
@ -147,12 +139,12 @@ void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataS
return;
}
if (pnode2->verifiedProRegTxHash == mnauth.proRegTxHash) {
if (pnode2->GetVerifiedProRegTxHash() == mnauth.proRegTxHash) {
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",
mnauth.proRegTxHash.ToString(), pnode2->GetId(), deterministicOutbound.ToString(), pnode->GetId());
if (deterministicOutbound == activeMasternodeInfo.proTxHash) {
if (WITH_LOCK(activeMasternodeInfoCs, return deterministicOutbound == activeMasternodeInfo.proTxHash)) {
if (pnode2->fInbound) {
LogPrint(BCLog::NET_NETCONN, "CMNAuth::ProcessMessage -- dropping old inbound, peer=%d\n", pnode2->GetId());
pnode2->fDisconnect = true;
@ -181,13 +173,10 @@ void CMNAuth::ProcessMessage(CNode* pnode, const std::string& strCommand, CDataS
return;
}
{
LOCK(pnode->cs_mnauth);
pnode->verifiedProRegTxHash = mnauth.proRegTxHash;
pnode->verifiedPubKeyHash = dmn->pdmnState->pubKeyOperator.GetHash();
}
pnode->SetVerifiedProRegTxHash(mnauth.proRegTxHash);
pnode->SetVerifiedPubKeyHash(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.
// 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
@ -209,11 +198,11 @@ void CMNAuth::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList&
}
g_connman->ForEachNode([&](CNode* pnode) {
LOCK(pnode->cs_mnauth);
if (pnode->verifiedProRegTxHash.IsNull()) {
auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (verifiedProRegTxHash.IsNull()) {
return;
}
auto verifiedDmn = oldMNList.GetMN(pnode->verifiedProRegTxHash);
auto verifiedDmn = oldMNList.GetMN(verifiedProRegTxHash);
if (!verifiedDmn) {
return;
}
@ -223,7 +212,7 @@ void CMNAuth::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList&
} else {
auto it = diff.updatedMNs.find(verifiedDmn->GetInternalId());
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;
}
}
@ -231,7 +220,7 @@ void CMNAuth::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList&
if (doRemove) {
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;
}
});

View File

@ -369,9 +369,12 @@ void PrepareShutdown()
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();
activeMasternodeInfo.blsPubKeyOperator.reset();
{
LOCK(activeMasternodeInfoCs);
// 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
try {
@ -2329,8 +2332,12 @@ bool AppInitMain()
return InitError(_("Invalid masternodeblsprivkey. Please see documentation."));
}
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(" blsPubKeyOperator: %s\n", keyOperator.GetPublicKey().ToString());
}
@ -2341,11 +2348,14 @@ bool AppInitMain()
RegisterValidationInterface(activeMasternodeManager);
}
if (activeMasternodeInfo.blsKeyOperator == nullptr) {
activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>();
}
if (activeMasternodeInfo.blsPubKeyOperator == nullptr) {
activeMasternodeInfo.blsPubKeyOperator = std::make_unique<CBLSPublicKey>();
{
LOCK(activeMasternodeInfoCs);
if (activeMasternodeInfo.blsKeyOperator == nullptr) {
activeMasternodeInfo.blsKeyOperator = std::make_unique<CBLSSecretKey>();
}
if (activeMasternodeInfo.blsPubKeyOperator == nullptr) {
activeMasternodeInfo.blsPubKeyOperator = std::make_unique<CBLSPublicKey>();
}
}
// ********************************************************* 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)
{
if (::SerializeHash(quorumVecIn) != qc->quorumVvecHash) {
const auto quorumVecInSerialized = ::SerializeHash(quorumVecIn);
LOCK(cs);
if (quorumVecInSerialized != qc->quorumVvecHash) {
return false;
}
quorumVvec = std::make_shared<BLSVerificationVector>(quorumVecIn);
@ -70,9 +73,10 @@ bool CQuorum::SetVerificationVector(const BLSVerificationVector& quorumVecIn)
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;
}
LOCK(cs);
skShare = secretKeyShare;
return true;
}
@ -99,15 +103,22 @@ bool CQuorum::IsValidMember(const uint256& proTxHash) 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();
}
auto& m = members[memberIdx];
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;
}
@ -125,7 +136,8 @@ void CQuorum::WriteContributions(CEvoDB& evoDb) const
{
uint256 dbKey = MakeQuorumKey(*this);
if (quorumVvec != nullptr) {
LOCK(cs);
if (HasVerificationVector()) {
evoDb.GetRawDB().Write(std::make_pair(DB_QUORUM_QUORUM_VVEC, dbKey), *quorumVvec);
}
if (skShare.IsValid()) {
@ -139,14 +151,14 @@ bool CQuorum::ReadContributions(CEvoDB& evoDb)
BLSVerificationVector 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 {
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
// 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;
}
@ -197,8 +209,10 @@ void CQuorumManager::TriggerQuorumDataRecoveryThreads(const CBlockIndex* pIndex)
// First check if we are member of any quorum of this type
bool fWeAreQuorumTypeMember{false};
auto proTxHash = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash);
for (const auto& pQuorum : vecQuorums) {
if (pQuorum->IsValidMember(activeMasternodeInfo.proTxHash)) {
if (pQuorum->IsValidMember(proTxHash)) {
fWeAreQuorumTypeMember = true;
break;
}
@ -211,16 +225,16 @@ void CQuorumManager::TriggerQuorumDataRecoveryThreads(const CBlockIndex* pIndex)
}
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 QvvecSyncMode syncMode = fSyncForTypeEnabled ? mapQuorumVvecSync.at(pQuorum->qc->llmqType) : QvvecSyncMode::Invalid;
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;
}
if (fWeAreQuorumMember && !pQuorum->skShare.IsValid()) {
if (fWeAreQuorumMember && !pQuorum->GetSkShare().IsValid()) {
nDataMask |= llmq::CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS;
}
@ -266,7 +280,6 @@ void CQuorumManager::EnsureQuorumConnections(Consensus::LLMQType llmqType, const
{
const auto& llmq_params = GetLLMQParams(llmqType);
const auto& myProTxHash = activeMasternodeInfo.proTxHash;
auto lastQuorums = ScanQuorums(llmqType, pindexNew, (size_t)llmq_params.keepOldConnections);
auto connmanQuorumsToDelete = g_connman->GetMasternodeQuorums(llmqType);
@ -277,7 +290,7 @@ void CQuorumManager::EnsureQuorumConnections(Consensus::LLMQType llmqType, const
connmanQuorumsToDelete.erase(curDkgBlock);
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;
}
if (connmanQuorumsToDelete.count(quorum->qc->quorumHash) > 0) {
@ -339,8 +352,9 @@ bool CQuorumManager::BuildQuorumContributions(const CFinalCommitmentPtr& fqc, co
}
cxxtimer::Timer t2(true);
LOCK(quorum->cs);
quorum->quorumVvec = blsWorker.BuildQuorumVerificationVector(vvecs);
if (quorum->quorumVvec == nullptr) {
if (!quorum->HasVerificationVector()) {
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
// 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);
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__);
return false;
}
@ -389,7 +403,7 @@ bool CQuorumManager::RequestQuorumData(CNode* pFrom, Consensus::LLMQType llmqTyp
}
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));
if (!it.second && !it.first->second.IsExpired()) {
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());
size_t nIndex{0};
for (size_t i = 0; i < vecProTxHashes.size(); ++i) {
if (activeMasternodeInfo.proTxHash == vecProTxHashes[i]) {
nIndex = i;
break;
{
LOCK(activeMasternodeInfoCs);
for (size_t i = 0; i < vecProTxHashes.size(); ++i) {
if (activeMasternodeInfo.proTxHash == vecProTxHashes[i]) {
nIndex = i;
break;
}
}
}
return nIndex % pQuorum->qc->validMembers.size();
@ -539,7 +556,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
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");
return;
}
@ -556,7 +573,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
{
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);
if (it == mapQuorumDataRequests.end()) {
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
if (request.GetDataMask() & CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR) {
if (!pQuorum->quorumVvec) {
if (!pQuorum->HasVerificationVector()) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_VERIFICATION_VECTOR_MISSING);
return;
}
ssResponseData << *pQuorum->quorumVvec;
WITH_LOCK(pQuorum->cs, ssResponseData << *pQuorum->quorumVvec);
}
// 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 ((!fMasternodeMode && !CLLMQUtils::IsWatchQuorumsEnabled()) || pFrom == nullptr || (pFrom->verifiedProRegTxHash.IsNull() && !pFrom->qwatch)) {
auto verifiedProRegTxHash = pFrom->GetVerifiedProRegTxHash();
if ((!fMasternodeMode && !CLLMQUtils::IsWatchQuorumsEnabled()) || pFrom == nullptr || (verifiedProRegTxHash.IsNull() && !pFrom->qwatch)) {
errorHandler("Not a verified masternode or a qwatch connection");
return;
}
@ -635,7 +651,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
{
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()) {
errorHandler("Not requested");
return;
@ -682,7 +698,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
// Check if request has ENCRYPTED_CONTRIBUTIONS data
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
return;
}
@ -698,8 +714,9 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
BLSSecretKeyVector vecSecretKeys;
vecSecretKeys.resize(vecEncrypted.size());
auto secret = WITH_LOCK(activeMasternodeInfoCs, return *activeMasternodeInfo.blsKeyOperator);
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");
return;
}
@ -718,7 +735,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& strCommand,
void CQuorumManager::StartCachePopulatorThread(const CQuorumCPtr pQuorum) const
{
if (pQuorum->quorumVvec == nullptr) {
if (!pQuorum->HasVerificationVector()) {
return;
}
@ -771,7 +788,7 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co
vecMemberHashes.reserve(pQuorum->qc->validMembers.size());
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);
}
}
@ -781,12 +798,13 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co
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;
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;
printLog("Received skShare");
}
@ -818,18 +836,19 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co
printLog("Connect");
}
auto proTxHash = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash);
g_connman->ForEachNode([&](CNode* pNode) {
if (pCurrentMemberHash == nullptr || pNode->verifiedProRegTxHash != *pCurrentMemberHash) {
auto verifiedProRegTxHash = pNode->GetVerifiedProRegTxHash();
if (pCurrentMemberHash == nullptr || verifiedProRegTxHash != *pCurrentMemberHash) {
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();
printLog("Requested");
} else {
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()) {
printLog("Failed");
pNode->fDisconnect = true;

View File

@ -157,16 +157,17 @@ public:
uint256 minedBlockHash;
std::vector<CDeterministicMNCPtr> members;
// These are only valid when we either participated in the DKG or fully watched it
BLSVerificationVectorPtr quorumVvec;
CBLSSecretKey skShare;
private:
// 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
mutable CBLSWorkerCache blsCache;
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:
CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker);
~CQuorum();
@ -175,12 +176,13 @@ public:
bool SetVerificationVector(const BLSVerificationVector& quorumVecIn);
bool SetSecretKeyShare(const CBLSSecretKey& secretKeyShare);
bool HasVerificationVector() const;
bool IsMember(const uint256& proTxHash) const;
bool IsValidMember(const uint256& proTxHash) const;
int GetMemberIndex(const uint256& proTxHash) const;
CBLSPublicKey GetPubKeyShare(size_t memberIdx) const;
const CBLSSecretKey& GetSkShare() const;
CBLSSecretKey GetSkShare() const;
private:
void WriteContributions(CEvoDB& evoDb) const;

View File

@ -199,7 +199,7 @@ void CDKGSession::SendContributions(CDKGPendingMessages& pendingMessages)
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();
@ -324,7 +324,7 @@ void CDKGSession::ReceiveMessage(const CDKGContribution& qc, bool& retBan)
bool complain = false;
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());
complain = true;
} else if (member->idx != myIdx && ShouldSimulateError("complain-lie")) {
@ -466,10 +466,11 @@ void CDKGSession::VerifyConnectionAndMinProtoVersions() const
std::unordered_map<uint256, int, StaticSaltedHasher> protoMap;
g_connman->ForEachNode([&](const CNode* pnode) {
if (pnode->verifiedProRegTxHash.IsNull()) {
auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (verifiedProRegTxHash.IsNull()) {
return;
}
protoMap.emplace(pnode->verifiedProRegTxHash, pnode->nVersion);
protoMap.emplace(verifiedProRegTxHash, pnode->nVersion);
});
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);
qc.sig = activeMasternodeInfo.blsKeyOperator->Sign(qc.GetSignHash());
qc.sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(qc.GetSignHash()));
logger.Flush();
@ -725,7 +726,7 @@ void CDKGSession::SendJustification(CDKGPendingMessages& pendingMessages, const
return;
}
qj.sig = activeMasternodeInfo.blsKeyOperator->Sign(qj.GetSignHash());
qj.sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(qj.GetSignHash()));
logger.Flush();
@ -1027,7 +1028,7 @@ void CDKGSession::SendCommitment(CDKGPendingMessages& pendingMessages)
(*commitmentHash.begin())++;
}
qc.sig = activeMasternodeInfo.blsKeyOperator->Sign(commitmentHash);
qc.sig = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsKeyOperator->Sign(commitmentHash));
qc.quorumSig = skShare.Sign(commitmentHash);
if (lieType == 3) {
@ -1334,9 +1335,10 @@ void CDKGSession::RelayInvToParticipants(const CInv& inv) const
LOCK(invCs);
g_connman->ForEachNode([&](CNode* pnode) {
bool relay = false;
auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (pnode->qwatch) {
relay = true;
} else if (!pnode->verifiedProRegTxHash.IsNull() && relayMembers.count(pnode->verifiedProRegTxHash)) {
} else if (!verifiedProRegTxHash.IsNull() && relayMembers.count(verifiedProRegTxHash)) {
relay = true;
}
if (relay) {

View File

@ -166,7 +166,7 @@ bool CDKGSessionHandler::InitNewQuorum(const CBlockIndex* 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);
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)
{
if (!fMasternodeMode || activeMasternodeInfo.proTxHash.IsNull()) {
if (!fMasternodeMode || WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash.IsNull())) {
return false;
}
@ -805,7 +805,7 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint
return false;
}
if (!quorum->IsValidMember(activeMasternodeInfo.proTxHash)) {
if (!WITH_LOCK(activeMasternodeInfoCs, return quorum->IsValidMember(activeMasternodeInfo.proTxHash))) {
return false;
}

View File

@ -234,7 +234,7 @@ void CSigSharesManager::InterruptWorkerThread()
void CSigSharesManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv)
{
// non-masternodes are not interested in sigshares
if (!fMasternodeMode || activeMasternodeInfo.proTxHash.IsNull()) {
if (!fMasternodeMode || WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash.IsNull())) {
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__,
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
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());
@ -485,11 +485,11 @@ void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& s
// quorum is too old
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)
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
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);
@ -534,11 +534,11 @@ bool CSigSharesManager::PreVerifyBatchedSigShares(const CSigSharesNodeState::Ses
// quorum is too old
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)
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
LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible.\n", __func__,
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
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);
}
@ -1018,10 +1018,11 @@ void CSigSharesManager::CollectSigSharesToSendConcentrated(std::unordered_map<No
std::unordered_map<uint256, CNode*> proTxToNode;
for (const auto& pnode : vNodes) {
if (pnode->verifiedProRegTxHash.IsNull()) {
auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (verifiedProRegTxHash.IsNull()) {
continue;
}
proTxToNode.emplace(pnode->verifiedProRegTxHash, pnode);
proTxToNode.emplace(verifiedProRegTxHash, pnode);
}
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
{
cxxtimer::Timer t(true);
auto activeMasterNodeProTxHash = WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash);
if (!quorum->IsValidMember(activeMasternodeInfo.proTxHash)) {
if (!quorum->IsValidMember(activeMasterNodeProTxHash)) {
return {};
}
@ -1578,7 +1580,7 @@ CSigShare CSigSharesManager::CreateSigShare(const CQuorumCPtr& quorum, const uin
return {};
}
int memberIdx = quorum->GetMemberIndex(activeMasternodeInfo.proTxHash);
int memberIdx = quorum->GetMemberIndex(activeMasterNodeProTxHash);
if (memberIdx == -1) {
// this should really not happen (IsValidMember gave true)
return {};

View File

@ -15,7 +15,8 @@
#include <bls/bls.h>
// Keep track of the active Masternode
CActiveMasternodeInfo activeMasternodeInfo;
CCriticalSection activeMasternodeInfoCs;
CActiveMasternodeInfo activeMasternodeInfo GUARDED_BY(activeMasternodeInfoCs);
CActiveMasternodeManager* activeMasternodeManager;
std::string CActiveMasternodeManager::GetStateString() const
@ -64,7 +65,7 @@ std::string CActiveMasternodeManager::GetStatus() const
void CActiveMasternodeManager::Init(const CBlockIndex* pindex)
{
LOCK(cs_main);
LOCK2(cs_main, activeMasternodeInfoCs);
if (!fMasternodeMode) return;
@ -136,7 +137,7 @@ void CActiveMasternodeManager::Init(const CBlockIndex* pindex)
void CActiveMasternodeManager::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload)
{
LOCK(cs_main);
LOCK2(cs_main, activeMasternodeInfoCs);
if (!fMasternodeMode) return;
@ -201,10 +202,11 @@ bool CActiveMasternodeManager::GetLocalAddress(CService& addrRet)
if (!fFoundLocal) {
bool empty = true;
// 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;
if (pnode->addr.IsIPv4())
fFoundLocal = GetLocal(activeMasternodeInfo.service, &pnode->addr) && IsValidNetAddr(activeMasternodeInfo.service);
fFoundLocal = GetLocal(service, &pnode->addr) && IsValidNetAddr(service);
return !fFoundLocal;
});
// nothing and no live connections, can't do anything for now

View File

@ -16,6 +16,7 @@ struct CActiveMasternodeInfo;
class CActiveMasternodeManager;
extern CActiveMasternodeInfo activeMasternodeInfo;
extern CCriticalSection activeMasternodeInfoCs;
extern CActiveMasternodeManager* activeMasternodeManager;
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
// checking incoming connection limits)
if (!node->verifiedProRegTxHash.IsNull()) {
if (!node->GetVerifiedProRegTxHash().IsNull()) {
isProtected = true;
}
if (isProtected) {
@ -1036,7 +1036,7 @@ void CConnman::AcceptConnection(const ListenSocket& hListenSocket) {
for (const CNode* pnode : vNodes) {
if (pnode->fInbound) {
nInbound++;
if (!pnode->verifiedProRegTxHash.IsNull()) {
if (!pnode->GetVerifiedProRegTxHash().IsNull()) {
nVerifiedInboundMasternodes++;
}
}
@ -2251,8 +2251,9 @@ void CConnman::ThreadOpenConnections(const std::vector<std::string> connect)
{
LOCK(cs_vNodes);
for (CNode* pnode : vNodes) {
if (!pnode->verifiedProRegTxHash.IsNull()) {
setConnectedMasternodes.emplace(pnode->verifiedProRegTxHash);
auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (!verifiedProRegTxHash.IsNull()) {
setConnectedMasternodes.emplace(verifiedProRegTxHash);
}
}
}
@ -2475,9 +2476,10 @@ void CConnman::ThreadOpenMasternodeConnections()
std::set<CService> connectedNodes;
std::map<uint256, bool> connectedProRegTxHashes;
ForEachNode([&](const CNode* pnode) {
auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
connectedNodes.emplace(pnode->addr);
if (!pnode->verifiedProRegTxHash.IsNull()) {
connectedProRegTxHashes.emplace(pnode->verifiedProRegTxHash, pnode->fInbound);
if (!verifiedProRegTxHash.IsNull()) {
connectedProRegTxHashes.emplace(verifiedProRegTxHash, pnode->fInbound);
}
});
@ -3344,7 +3346,8 @@ void CConnman::SetMasternodeQuorumRelayMembers(Consensus::LLMQType llmqType, con
// Update existing connections
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.
// 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
@ -3389,7 +3392,8 @@ std::set<NodeId> CConnman::GetMasternodeQuorumNodes(Consensus::LLMQType llmqType
if (pnode->fDisconnect) {
continue;
}
if (!pnode->qwatch && (pnode->verifiedProRegTxHash.IsNull() || !proRegTxHashes.count(pnode->verifiedProRegTxHash))) {
auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
if (!pnode->qwatch && (verifiedProRegTxHash.IsNull() || !proRegTxHashes.count(verifiedProRegTxHash))) {
continue;
}
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
// We however only need to know this if the node did not authenticate itself as a MN yet
uint256 assumedProTxHash;
if (pnode->verifiedProRegTxHash.IsNull() && !pnode->fInbound) {
if (pnode->GetVerifiedProRegTxHash().IsNull() && !pnode->fInbound) {
auto mnList = deterministicMNManager->GetListAtChainTip();
auto dmn = mnList.GetMNByService(pnode->addr);
if (dmn == nullptr) {
@ -3421,8 +3425,8 @@ bool CConnman::IsMasternodeQuorumNode(const CNode* pnode)
LOCK(cs_vPendingMasternodes);
for (const auto& p : masternodeQuorumNodes) {
if (!pnode->verifiedProRegTxHash.IsNull()) {
if (p.second.count(pnode->verifiedProRegTxHash)) {
if (!pnode->GetVerifiedProRegTxHash().IsNull()) {
if (p.second.count(pnode->GetVerifiedProRegTxHash())) {
return true;
}
} else if (!assumedProTxHash.IsNull()) {

View File

@ -905,11 +905,11 @@ public:
bool fRelayTxes; //protected by cs_filter
bool fSentAddr;
// 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
bool m_masternode_probe_connection;
std::atomic<bool> m_masternode_probe_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;
CCriticalSection cs_filter;
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
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)
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
@ -1015,6 +1008,14 @@ private:
// Our address, as reported by the peer
CService addrLocal GUARDED_BY(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:
NodeId GetId() const {
@ -1148,6 +1149,46 @@ public:
std::string GetLogString() const;
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

View File

@ -438,10 +438,7 @@ static void PushNodeVersion(CNode *pnode, CConnman* connman, int64_t nTime)
uint256 mnauthChallenge;
GetRandBytes(mnauthChallenge.begin(), mnauthChallenge.size());
{
LOCK(pnode->cs_mnauth);
pnode->sentMNAuthChallenge = mnauthChallenge;
}
pnode->SetSentMNAuthChallenge(mnauthChallenge);
int nProtocolVersion = PROTOCOL_VERSION;
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,
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) {
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())
vRecv >> fRelay;
if (!vRecv.empty()) {
LOCK(pfrom->cs_mnauth);
vRecv >> pfrom->receivedMNAuthChallenge;
uint256 receivedMNAuthChallenge;
vRecv >> receivedMNAuthChallenge;
pfrom->SetReceivedMNAuthChallenge(receivedMNAuthChallenge);
}
if (!vRecv.empty()) {
bool fOtherMasternode = false;
@ -4283,7 +4281,7 @@ bool PeerLogicValidation::SendMessages(CNode* pto)
} else {
// 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.
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();
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",
(activeMasternodeInfo.blsPubKeyOperator ? activeMasternodeInfo.blsPubKeyOperator->ToString() : "N/A"),
activeMasternodeInfo.outpoint.ToStringShort(), request.params.size(), fMnFound);
(WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.blsPubKeyOperator ? activeMasternodeInfo.blsPubKeyOperator->ToString() : "N/A")),
WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.outpoint.ToStringShort()), request.params.size(), fMnFound);
// 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
if (govobj.GetObjectType() == GOVERNANCE_OBJECT_TRIGGER) {
if (fMnFound) {
LOCK(activeMasternodeInfoCs);
govobj.SetMasternodeOutpoint(activeMasternodeInfo.outpoint);
govobj.Sign(*activeMasternodeInfo.blsKeyOperator);
} else {
@ -450,7 +451,7 @@ static UniValue gobject_vote_conf(const JSONRPCRequest& request)
UniValue statusObj(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) {
nFailed++;
@ -468,8 +469,12 @@ static UniValue gobject_vote_conf(const JSONRPCRequest& request)
if (govObjType == GOVERNANCE_OBJECT_PROPOSAL && eVoteSignal == VOTE_SIGNAL_FUNDING) {
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) {

View File

@ -233,11 +233,15 @@ static UniValue masternode_status(const JSONRPCRequest& request)
UniValue mnObj(UniValue::VOBJ);
// keep compatibility with legacy status for now (might get deprecated/removed later)
mnObj.pushKV("outpoint", activeMasternodeInfo.outpoint.ToStringShort());
mnObj.pushKV("service", activeMasternodeInfo.service.ToString());
CDeterministicMNCPtr dmn;
{
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) {
mnObj.pushKV("proTxHash", dmn->proTxHash.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){
LOCK(pNode->cs_mnauth);
pNode->verifiedProRegTxHash = proTxHash;
pNode->verifiedPubKeyHash = publicKey.GetHash();
pNode->SetVerifiedProRegTxHash(proTxHash);
pNode->SetVerifiedPubKeyHash(publicKey.GetHash());
return true;
});

View File

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

View File

@ -25,7 +25,7 @@
#include <unordered_map>
static CCriticalSection cs_rpcWarmup;
static bool fRPCRunning = false;
static std::atomic<bool> fRPCRunning{false};
static bool fRPCInWarmup GUARDED_BY(cs_rpcWarmup) = true;
static std::string rpcWarmupStatus GUARDED_BY(cs_rpcWarmup) = "RPC server started";
/* 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)
{
// Remove from key pool
WalletBatch batch(*database);
if (batch.ErasePool(nIndex))
--nKeysLeftSinceAutoBackup;
if (!nWalletBackups)
nKeysLeftSinceAutoBackup = 0;
{
LOCK(cs_wallet);
WalletBatch batch(*database);
if (batch.ErasePool(nIndex))
--nKeysLeftSinceAutoBackup;
if (!nWalletBackups)
nKeysLeftSinceAutoBackup = 0;
}
WalletLogPrintf("keypool keep %d\n", nIndex);
}