mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
Merge #5961: feat: implement read write locks in threading and use them for CActiveMasternodeManager::cs
069282611c
refactor: make CActiveMasternodeManager::cs SharedMutex and private (pasta)663774c544
feat: implement Read Write Locks in threading (pasta) Pull request description: ## Issue being fixed or feature implemented We have some caches or other information in codebase which are read from a lot; but rarely written to. We can use a RW lock here instead of a normal Mutex ## What was done? Implement a RW lock and use them ## How Has This Been Tested? Hasn't been much; looking for review atm. Maybe should deploy this on testnet for a bit and make sure it doesn't break. ## Breaking Changes ## Checklist: _Go over all the following points, and put an `x` in all the boxes that apply._ - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_ ACKs for top commit: knst: utACK069282611c
Tree-SHA512: a9759d4904580eebb5ddf9e05d3d54cf4b0b0db971f09d2f4cb093fddc0a13094998ef2af301de581fd64dc1235df80bace7f701ab437c2ecfa663b4fc6e25ed
This commit is contained in:
commit
dc6f52ac99
@ -58,7 +58,7 @@ void CCoinJoinServer::ProcessDSACCEPT(CNode& peer, CDataStream& vRecv)
|
||||
LogPrint(BCLog::COINJOIN, "DSACCEPT -- nDenom %d (%s) txCollateral %s", dsa.nDenom, CoinJoin::DenominationToString(dsa.nDenom), dsa.txCollateral.ToString()); /* Continued */
|
||||
|
||||
auto mnList = m_dmnman.GetListAtChainTip();
|
||||
auto dmn = WITH_LOCK(m_mn_activeman->cs, return mnList.GetValidMNByCollateral(m_mn_activeman->GetOutPoint()));
|
||||
auto dmn = mnList.GetValidMNByCollateral(m_mn_activeman->GetOutPoint());
|
||||
if (!dmn) {
|
||||
PushStatus(peer, STATUS_REJECTED, ERR_MN_LIST);
|
||||
return;
|
||||
@ -69,7 +69,7 @@ void CCoinJoinServer::ProcessDSACCEPT(CNode& peer, CDataStream& vRecv)
|
||||
TRY_LOCK(cs_vecqueue, lockRecv);
|
||||
if (!lockRecv) return;
|
||||
|
||||
auto mnOutpoint = WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetOutPoint());
|
||||
auto mnOutpoint = m_mn_activeman->GetOutPoint();
|
||||
|
||||
if (ranges::any_of(vecCoinJoinQueue,
|
||||
[&mnOutpoint](const auto& q){return q.masternodeOutpoint == mnOutpoint;})) {
|
||||
@ -335,8 +335,8 @@ void CCoinJoinServer::CommitFinalTransaction()
|
||||
// create and sign masternode dstx transaction
|
||||
if (!m_dstxman.GetDSTX(hashTx)) {
|
||||
CCoinJoinBroadcastTx dstxNew(finalTransaction,
|
||||
WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetOutPoint()),
|
||||
WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash()),
|
||||
m_mn_activeman->GetOutPoint(),
|
||||
m_mn_activeman->GetProTxHash(),
|
||||
GetAdjustedTime());
|
||||
dstxNew.Sign(*m_mn_activeman);
|
||||
m_dstxman.AddDSTX(dstxNew);
|
||||
@ -505,8 +505,8 @@ void CCoinJoinServer::CheckForCompleteQueue()
|
||||
SetState(POOL_STATE_ACCEPTING_ENTRIES);
|
||||
|
||||
CCoinJoinQueue dsq(nSessionDenom,
|
||||
WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetOutPoint()),
|
||||
WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash()),
|
||||
m_mn_activeman->GetOutPoint(),
|
||||
m_mn_activeman->GetProTxHash(),
|
||||
GetAdjustedTime(), true);
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CheckForCompleteQueue -- queue is ready, signing and relaying (%s) " /* Continued */
|
||||
"with %d participants\n", dsq.ToString(), vecSessionCollaterals.size());
|
||||
@ -721,8 +721,8 @@ 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,
|
||||
WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetOutPoint()),
|
||||
WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash()),
|
||||
m_mn_activeman->GetOutPoint(),
|
||||
m_mn_activeman->GetProTxHash(),
|
||||
GetAdjustedTime(), false);
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CreateNewSession -- signing and relaying new queue: %s\n", dsq.ToString());
|
||||
dsq.Sign(*m_mn_activeman);
|
||||
|
@ -24,38 +24,36 @@ void CMNAuth::PushMNAUTH(CNode& peer, CConnman& connman, const CBlockIndex* tip)
|
||||
if (!fMasternodeMode) return;
|
||||
|
||||
CMNAuth mnauth;
|
||||
uint256 signHash;
|
||||
{
|
||||
LOCK(::activeMasternodeManager->cs);
|
||||
if (::activeMasternodeManager->GetProTxHash().IsNull()) {
|
||||
return;
|
||||
}
|
||||
if (::activeMasternodeManager->GetProTxHash().IsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto receivedMNAuthChallenge = peer.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);
|
||||
}
|
||||
const bool is_basic_scheme_active{DeploymentActiveAfter(tip, Params().GetConsensus(), Consensus::DEPLOYMENT_V19)};
|
||||
auto pk = ::activeMasternodeManager->GetPubKey();
|
||||
const CBLSPublicKeyVersionWrapper pubKey(pk, !is_basic_scheme_active);
|
||||
const auto receivedMNAuthChallenge = peer.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);
|
||||
}
|
||||
const bool is_basic_scheme_active{DeploymentActiveAfter(tip, Params().GetConsensus(), Consensus::DEPLOYMENT_V19)};
|
||||
auto pk = ::activeMasternodeManager->GetPubKey();
|
||||
const CBLSPublicKeyVersionWrapper pubKey(pk, !is_basic_scheme_active);
|
||||
uint256 signHash = [&]() {
|
||||
if (peer.nVersion < MNAUTH_NODE_VER_VERSION || nOurNodeVersion < MNAUTH_NODE_VER_VERSION) {
|
||||
signHash = ::SerializeHash(std::make_tuple(pubKey, receivedMNAuthChallenge, peer.IsInboundConn()));
|
||||
return ::SerializeHash(std::make_tuple(pubKey, receivedMNAuthChallenge, peer.IsInboundConn()));
|
||||
} else {
|
||||
signHash = ::SerializeHash(std::make_tuple(pubKey, receivedMNAuthChallenge, peer.IsInboundConn(), nOurNodeVersion));
|
||||
return ::SerializeHash(std::make_tuple(pubKey, receivedMNAuthChallenge, peer.IsInboundConn(), nOurNodeVersion));
|
||||
}
|
||||
}();
|
||||
|
||||
mnauth.proRegTxHash = ::activeMasternodeManager->GetProTxHash();
|
||||
} // ::activeMasternodeManager->cs
|
||||
mnauth.proRegTxHash = ::activeMasternodeManager->GetProTxHash();
|
||||
|
||||
mnauth.sig = ::activeMasternodeManager->Sign(signHash);
|
||||
|
||||
@ -133,7 +131,7 @@ PeerMsgRet CMNAuth::ProcessMessage(CNode& peer, CConnman& connman, const CDeterm
|
||||
}
|
||||
|
||||
const uint256 myProTxHash = fMasternodeMode ?
|
||||
WITH_LOCK(::activeMasternodeManager->cs, return ::activeMasternodeManager->GetProTxHash()) :
|
||||
::activeMasternodeManager->GetProTxHash() :
|
||||
uint256();
|
||||
|
||||
connman.ForEachNode([&](CNode* pnode2) {
|
||||
|
@ -691,14 +691,11 @@ std::optional<const CGovernanceObject> CGovernanceManager::CreateGovernanceTrigg
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
{
|
||||
LOCK(::activeMasternodeManager->cs);
|
||||
if (mn_payees.front()->proTxHash != ::activeMasternodeManager->GetProTxHash()) {
|
||||
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s we are not the payee, skipping\n", __func__);
|
||||
return std::nullopt;
|
||||
}
|
||||
gov_sb.SetMasternodeOutpoint(::activeMasternodeManager->GetOutPoint());
|
||||
} // ::activeMasternodeManager->cs
|
||||
if (mn_payees.front()->proTxHash != ::activeMasternodeManager->GetProTxHash()) {
|
||||
LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s we are not the payee, skipping\n", __func__);
|
||||
return std::nullopt;
|
||||
}
|
||||
gov_sb.SetMasternodeOutpoint(::activeMasternodeManager->GetOutPoint());
|
||||
gov_sb.Sign(*::activeMasternodeManager);
|
||||
|
||||
if (std::string strError; !gov_sb.IsValidLocally(m_dmnman->GetListAtChainTip(), strError, true)) {
|
||||
@ -720,7 +717,7 @@ void CGovernanceManager::VoteGovernanceTriggers(const std::optional<const CGover
|
||||
{
|
||||
// only active masternodes can vote on triggers
|
||||
if (!fMasternodeMode) return;
|
||||
if (WITH_LOCK(::activeMasternodeManager->cs, return ::activeMasternodeManager->GetProTxHash().IsNull())) return;
|
||||
if (::activeMasternodeManager->GetProTxHash().IsNull()) return;
|
||||
|
||||
LOCK2(cs_main, cs);
|
||||
|
||||
@ -763,7 +760,7 @@ void CGovernanceManager::VoteGovernanceTriggers(const std::optional<const CGover
|
||||
|
||||
bool CGovernanceManager::VoteFundingTrigger(const uint256& nHash, const vote_outcome_enum_t outcome, CConnman& connman)
|
||||
{
|
||||
CGovernanceVote vote(WITH_LOCK(::activeMasternodeManager->cs, return ::activeMasternodeManager->GetOutPoint()), nHash, VOTE_SIGNAL_FUNDING, outcome);
|
||||
CGovernanceVote vote(::activeMasternodeManager->GetOutPoint(), nHash, VOTE_SIGNAL_FUNDING, outcome);
|
||||
vote.SetTime(GetAdjustedTime());
|
||||
vote.Sign(*::activeMasternodeManager);
|
||||
|
||||
|
@ -194,7 +194,7 @@ bool CDKGSessionHandler::InitNewQuorum(const CBlockIndex* pQuorumBaseBlockIndex)
|
||||
}
|
||||
|
||||
auto mns = utils::GetAllQuorumMembers(params.type, m_dmnman, pQuorumBaseBlockIndex);
|
||||
if (!curSession->Init(pQuorumBaseBlockIndex, mns, WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash()), quorumIndex)) {
|
||||
if (!curSession->Init(pQuorumBaseBlockIndex, mns, m_mn_activeman->GetProTxHash(), quorumIndex)) {
|
||||
LogPrintf("CDKGSessionManager::%s -- height[%d] quorum initialization failed for %s qi[%d] mns[%d]\n", __func__, pQuorumBaseBlockIndex->nHeight, curSession->params.name, quorumIndex, mns.size());
|
||||
return false;
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ bool CQuorum::SetVerificationVector(const std::vector<CBLSPublicKey>& quorumVecI
|
||||
|
||||
bool CQuorum::SetSecretKeyShare(const CBLSSecretKey& secretKeyShare, const CActiveMasternodeManager& mn_activeman)
|
||||
{
|
||||
if (!secretKeyShare.IsValid() || (secretKeyShare.GetPublicKey() != GetPubKeyShare(WITH_LOCK(mn_activeman.cs, return GetMemberIndex(mn_activeman.GetProTxHash()))))) {
|
||||
if (!secretKeyShare.IsValid() || (secretKeyShare.GetPublicKey() != GetPubKeyShare(GetMemberIndex(mn_activeman.GetProTxHash())))) {
|
||||
return false;
|
||||
}
|
||||
LOCK(cs);
|
||||
@ -256,7 +256,7 @@ void CQuorumManager::TriggerQuorumDataRecoveryThreads(const CBlockIndex* pIndex)
|
||||
const uint256 proTxHash = [this]() {
|
||||
if (!fMasternodeMode) return uint256();
|
||||
assert(m_mn_activeman);
|
||||
return WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash());
|
||||
return m_mn_activeman->GetProTxHash();
|
||||
}();
|
||||
|
||||
bool fWeAreQuorumTypeMember = ranges::any_of(vecQuorums, [&proTxHash](const auto& pQuorum) {
|
||||
@ -352,7 +352,7 @@ void CQuorumManager::CheckQuorumConnections(const Consensus::LLMQParams& llmqPar
|
||||
const uint256 myProTxHash = [this]() {
|
||||
if (!fMasternodeMode) return uint256();
|
||||
assert(m_mn_activeman);
|
||||
return WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash());
|
||||
return m_mn_activeman->GetProTxHash();
|
||||
}();
|
||||
|
||||
bool isISType = llmqParams.type == Params().GetConsensus().llmqTypeDIP0024InstantSend;
|
||||
@ -664,10 +664,10 @@ size_t CQuorumManager::GetQuorumRecoveryStartOffset(const CQuorumCPtr pQuorum, c
|
||||
std::sort(vecProTxHashes.begin(), vecProTxHashes.end());
|
||||
size_t nIndex{0};
|
||||
{
|
||||
LOCK(m_mn_activeman->cs);
|
||||
auto my_protx_hash = m_mn_activeman->GetProTxHash();
|
||||
for (const auto i : irange::range(vecProTxHashes.size())) {
|
||||
// cppcheck-suppress useStlAlgorithm
|
||||
if (m_mn_activeman->GetProTxHash() == vecProTxHashes[i]) {
|
||||
if (my_protx_hash == vecProTxHashes[i]) {
|
||||
nIndex = i;
|
||||
break;
|
||||
}
|
||||
@ -928,7 +928,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 != WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash())) {
|
||||
if (pQuorum->IsValidMember(member->proTxHash) && member->proTxHash != m_mn_activeman->GetProTxHash()) {
|
||||
vecMemberHashes.push_back(member->proTxHash);
|
||||
}
|
||||
}
|
||||
@ -977,7 +977,7 @@ void CQuorumManager::StartQuorumDataRecoveryThread(const CQuorumCPtr pQuorum, co
|
||||
printLog("Connect");
|
||||
}
|
||||
|
||||
auto proTxHash = WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash());
|
||||
auto proTxHash = m_mn_activeman->GetProTxHash();
|
||||
connman.ForEachNode([&](CNode* pNode) {
|
||||
auto verifiedProRegTxHash = pNode->GetVerifiedProRegTxHash();
|
||||
if (pCurrentMemberHash == nullptr || verifiedProRegTxHash != *pCurrentMemberHash) {
|
||||
|
@ -898,7 +898,7 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, CSigShares
|
||||
if (!fMasternodeMode) return false;
|
||||
|
||||
assert(m_mn_activeman);
|
||||
if (WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash().IsNull())) return false;
|
||||
if (m_mn_activeman->GetProTxHash().IsNull()) return false;
|
||||
|
||||
const CQuorumCPtr quorum = [&]() {
|
||||
if (quorumHash.IsNull()) {
|
||||
@ -920,7 +920,7 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, CSigShares
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!WITH_LOCK(m_mn_activeman->cs, return quorum->IsValidMember(m_mn_activeman->GetProTxHash()))) {
|
||||
if (!quorum->IsValidMember(m_mn_activeman->GetProTxHash())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ void CSigSharesManager::ProcessMessage(const CNode& pfrom, const CSporkManager&
|
||||
if (!fMasternodeMode) return;
|
||||
|
||||
assert(m_mn_activeman);
|
||||
if (WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash().IsNull())) return;
|
||||
if (m_mn_activeman->GetProTxHash().IsNull()) return;
|
||||
|
||||
if (sporkman.IsSporkActive(SPORK_21_QUORUM_ALL_CONNECTED) && msg_type == NetMsgType::QSIGSHARE) {
|
||||
std::vector<CSigShare> receivedSigShares;
|
||||
@ -468,7 +468,7 @@ void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& s
|
||||
// quorum is too old
|
||||
return;
|
||||
}
|
||||
if (!quorum->IsMember(WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash()))) {
|
||||
if (!quorum->IsMember(m_mn_activeman->GetProTxHash())) {
|
||||
// we're not a member so we can't verify it (we actually shouldn't have received it)
|
||||
return;
|
||||
}
|
||||
@ -518,7 +518,7 @@ bool CSigSharesManager::PreVerifyBatchedSigShares(const CActiveMasternodeManager
|
||||
// quorum is too old
|
||||
return false;
|
||||
}
|
||||
if (!session.quorum->IsMember(WITH_LOCK(mn_activeman.cs, return mn_activeman.GetProTxHash()))) {
|
||||
if (!session.quorum->IsMember(mn_activeman.GetProTxHash())) {
|
||||
// we're not a member so we can't verify it (we actually shouldn't have received it)
|
||||
return false;
|
||||
}
|
||||
@ -703,7 +703,7 @@ void CSigSharesManager::ProcessSigShare(const CSigShare& sigShare, const CConnma
|
||||
|
||||
// prepare node set for direct-push in case this is our sig share
|
||||
std::set<NodeId> quorumNodes;
|
||||
if (!IsAllMembersConnectedEnabled(llmqType, m_sporkman) && sigShare.getQuorumMember() == quorum->GetMemberIndex(WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash()))) {
|
||||
if (!IsAllMembersConnectedEnabled(llmqType, m_sporkman) && sigShare.getQuorumMember() == quorum->GetMemberIndex(m_mn_activeman->GetProTxHash())) {
|
||||
quorumNodes = connman.GetMasternodeQuorumNodes(sigShare.getLlmqType(), sigShare.getQuorumHash());
|
||||
}
|
||||
|
||||
@ -1496,7 +1496,7 @@ std::optional<CSigShare> CSigSharesManager::CreateSigShare(const CQuorumCPtr& qu
|
||||
assert(m_mn_activeman);
|
||||
|
||||
cxxtimer::Timer t(true);
|
||||
auto activeMasterNodeProTxHash = WITH_LOCK(m_mn_activeman->cs, return m_mn_activeman->GetProTxHash());
|
||||
auto activeMasterNodeProTxHash = m_mn_activeman->GetProTxHash();
|
||||
|
||||
if (!quorum->IsValidMember(activeMasterNodeProTxHash)) {
|
||||
return std::nullopt;
|
||||
|
@ -31,7 +31,7 @@ CActiveMasternodeManager::CActiveMasternodeManager(const CBLSSecretKey& sk, CCon
|
||||
|
||||
std::string CActiveMasternodeManager::GetStateString() const
|
||||
{
|
||||
switch (WITH_LOCK(cs, return m_state)) {
|
||||
switch (WITH_READ_LOCK(cs, return m_state)) {
|
||||
case MASTERNODE_WAITING_FOR_PROTX:
|
||||
return "WAITING_FOR_PROTX";
|
||||
case MASTERNODE_POSE_BANNED:
|
||||
@ -53,7 +53,7 @@ std::string CActiveMasternodeManager::GetStateString() const
|
||||
|
||||
std::string CActiveMasternodeManager::GetStatus() const
|
||||
{
|
||||
LOCK(cs);
|
||||
READ_LOCK(cs);
|
||||
switch (m_state) {
|
||||
case MASTERNODE_WAITING_FOR_PROTX:
|
||||
return "Waiting for ProTx to appear on-chain";
|
||||
@ -74,9 +74,9 @@ std::string CActiveMasternodeManager::GetStatus() const
|
||||
}
|
||||
}
|
||||
|
||||
void CActiveMasternodeManager::Init(const CBlockIndex* pindex)
|
||||
void CActiveMasternodeManager::InitInternal(const CBlockIndex* pindex)
|
||||
{
|
||||
LOCK(cs);
|
||||
AssertLockHeld(cs);
|
||||
|
||||
if (!fMasternodeMode) return;
|
||||
|
||||
@ -153,7 +153,7 @@ void CActiveMasternodeManager::UpdatedBlockTip(const CBlockIndex* pindexNew, con
|
||||
|
||||
if (!DeploymentDIP0003Enforced(pindexNew->nHeight, Params().GetConsensus())) return;
|
||||
|
||||
const auto [cur_state, cur_protx_hash] = WITH_LOCK(cs, return std::make_pair(m_state, m_info.proTxHash));
|
||||
const auto [cur_state, cur_protx_hash] = WITH_READ_LOCK(cs, return std::make_pair(m_state, m_info.proTxHash));
|
||||
if (cur_state == MASTERNODE_READY) {
|
||||
auto oldMNList = Assert(m_dmnman)->GetListForBlock(pindexNew->pprev);
|
||||
auto newMNList = m_dmnman->GetListForBlock(pindexNew);
|
||||
@ -163,7 +163,7 @@ void CActiveMasternodeManager::UpdatedBlockTip(const CBlockIndex* pindexNew, con
|
||||
m_info.proTxHash = uint256();
|
||||
m_info.outpoint.SetNull();
|
||||
// MN might have reappeared in same block with a new ProTx
|
||||
Init(pindexNew);
|
||||
InitInternal(pindexNew);
|
||||
};
|
||||
|
||||
if (!newMNList.IsMNValid(cur_protx_hash)) {
|
||||
@ -190,6 +190,7 @@ void CActiveMasternodeManager::UpdatedBlockTip(const CBlockIndex* pindexNew, con
|
||||
|
||||
bool CActiveMasternodeManager::GetLocalAddress(CService& addrRet)
|
||||
{
|
||||
AssertLockHeld(cs);
|
||||
// First try to find whatever our own local address is known internally.
|
||||
// Addresses could be specified via externalip or bind option, discovered via UPnP
|
||||
// or added by TorController. Use some random dummy IPv4 peer to prefer the one
|
||||
@ -207,7 +208,7 @@ 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
|
||||
auto service = WITH_LOCK(cs, return m_info.service);
|
||||
auto service = m_info.service;
|
||||
m_connman.ForEachNodeContinueIf(CConnman::AllNodes, [&](CNode* pnode) {
|
||||
empty = false;
|
||||
if (pnode->addr.IsIPv4())
|
||||
@ -216,7 +217,6 @@ bool CActiveMasternodeManager::GetLocalAddress(CService& addrRet)
|
||||
});
|
||||
// nothing and no live connections, can't do anything for now
|
||||
if (empty) {
|
||||
LOCK(cs);
|
||||
m_error = "Can't detect valid external address. Please consider using the externalip configuration option if problem persists. Make sure to use IPv4 address only.";
|
||||
LogPrintf("CActiveMasternodeManager::GetLocalAddress -- ERROR: %s\n", m_error);
|
||||
return false;
|
||||
@ -238,7 +238,7 @@ template <template <typename> class EncryptedObj, typename Obj>
|
||||
int version) const
|
||||
{
|
||||
AssertLockNotHeld(cs);
|
||||
return WITH_LOCK(cs, return obj.Decrypt(idx, m_info.blsKeyOperator, ret_obj, version));
|
||||
return WITH_READ_LOCK(cs, return obj.Decrypt(idx, m_info.blsKeyOperator, ret_obj, version));
|
||||
}
|
||||
template bool CActiveMasternodeManager::Decrypt(const CBLSIESEncryptedObject<CBLSSecretKey>& obj, size_t idx,
|
||||
CBLSSecretKey& ret_obj, int version) const;
|
||||
@ -248,18 +248,19 @@ template bool CActiveMasternodeManager::Decrypt(const CBLSIESMultiRecipientObjec
|
||||
[[nodiscard]] CBLSSignature CActiveMasternodeManager::Sign(const uint256& hash) const
|
||||
{
|
||||
AssertLockNotHeld(cs);
|
||||
return WITH_LOCK(cs, return m_info.blsKeyOperator.Sign(hash));
|
||||
return WITH_READ_LOCK(cs, return m_info.blsKeyOperator.Sign(hash));
|
||||
}
|
||||
|
||||
[[nodiscard]] CBLSSignature CActiveMasternodeManager::Sign(const uint256& hash, const bool is_legacy) const
|
||||
{
|
||||
AssertLockNotHeld(cs);
|
||||
return WITH_LOCK(cs, return m_info.blsKeyOperator.Sign(hash, is_legacy));
|
||||
return WITH_READ_LOCK(cs, return m_info.blsKeyOperator.Sign(hash, is_legacy));
|
||||
}
|
||||
|
||||
// We need to pass a copy as opposed to a const ref because CBLSPublicKeyVersionWrapper
|
||||
// does not accept a const ref in its construction args
|
||||
[[nodiscard]] CBLSPublicKey CActiveMasternodeManager::GetPubKey() const
|
||||
{
|
||||
READ_LOCK(cs);
|
||||
return m_info.blsPubKeyOperator;
|
||||
}
|
||||
|
@ -41,9 +41,8 @@ public:
|
||||
MASTERNODE_ERROR,
|
||||
};
|
||||
|
||||
mutable RecursiveMutex cs;
|
||||
|
||||
private:
|
||||
mutable SharedMutex cs;
|
||||
masternode_state_t m_state GUARDED_BY(cs) {MASTERNODE_WAITING_FOR_PROTX};
|
||||
CActiveMasternodeInfo m_info GUARDED_BY(cs);
|
||||
std::string m_error GUARDED_BY(cs);
|
||||
@ -56,7 +55,7 @@ public:
|
||||
|
||||
void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override;
|
||||
|
||||
void Init(const CBlockIndex* pindex);
|
||||
void Init(const CBlockIndex* pindex) LOCKS_EXCLUDED(cs) { LOCK(cs); InitInternal(pindex); };
|
||||
|
||||
std::string GetStateString() const;
|
||||
std::string GetStatus() const;
|
||||
@ -70,14 +69,15 @@ public:
|
||||
[[nodiscard]] CBLSSignature Sign(const uint256& hash, const bool is_legacy) const LOCKS_EXCLUDED(cs);
|
||||
|
||||
/* TODO: Reconsider external locking */
|
||||
[[nodiscard]] const COutPoint& GetOutPoint() const EXCLUSIVE_LOCKS_REQUIRED(cs) { return m_info.outpoint; }
|
||||
[[nodiscard]] const uint256& GetProTxHash() const EXCLUSIVE_LOCKS_REQUIRED(cs) { return m_info.proTxHash; }
|
||||
[[nodiscard]] const CService& GetService() const EXCLUSIVE_LOCKS_REQUIRED(cs) { return m_info.service; }
|
||||
[[nodiscard]] CBLSPublicKey GetPubKey() const EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
[[nodiscard]] bool IsLegacy() const EXCLUSIVE_LOCKS_REQUIRED(cs) { return m_info.legacy; }
|
||||
[[nodiscard]] COutPoint GetOutPoint() const { READ_LOCK(cs); return m_info.outpoint; }
|
||||
[[nodiscard]] uint256 GetProTxHash() const { READ_LOCK(cs); return m_info.proTxHash; }
|
||||
[[nodiscard]] CService GetService() const { READ_LOCK(cs); return m_info.service; }
|
||||
[[nodiscard]] CBLSPublicKey GetPubKey() const;
|
||||
[[nodiscard]] bool IsLegacy() const { READ_LOCK(cs); return m_info.legacy; }
|
||||
|
||||
private:
|
||||
bool GetLocalAddress(CService& addrRet);
|
||||
void InitInternal(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
bool GetLocalAddress(CService& addrRet) EXCLUSIVE_LOCKS_REQUIRED(cs);
|
||||
};
|
||||
|
||||
extern std::unique_ptr<CActiveMasternodeManager> activeMasternodeManager;
|
||||
|
@ -319,7 +319,6 @@ static UniValue gobject_submit(const JSONRPCRequest& request)
|
||||
if (fMasternodeMode) {
|
||||
CHECK_NONFATAL(node.mn_activeman);
|
||||
|
||||
LOCK(node.mn_activeman->cs);
|
||||
const bool fMnFound = mnList.HasValidMNByCollateral(node.mn_activeman->GetOutPoint());
|
||||
|
||||
LogPrint(BCLog::GOBJECT, "gobject_submit -- pubKeyOperator = %s, outpoint = %s, params.size() = %lld, fMnFound = %d\n",
|
||||
|
@ -265,15 +265,10 @@ static UniValue masternode_status(const JSONRPCRequest& request)
|
||||
CHECK_NONFATAL(node.mn_activeman);
|
||||
|
||||
UniValue mnObj(UniValue::VOBJ);
|
||||
CDeterministicMNCPtr dmn;
|
||||
{
|
||||
LOCK(node.mn_activeman->cs);
|
||||
|
||||
// keep compatibility with legacy status for now (might get deprecated/removed later)
|
||||
mnObj.pushKV("outpoint", node.mn_activeman->GetOutPoint().ToStringShort());
|
||||
mnObj.pushKV("service", node.mn_activeman->GetService().ToString());
|
||||
dmn = node.dmnman->GetListAtChainTip().GetMN(node.mn_activeman->GetProTxHash());
|
||||
}
|
||||
// keep compatibility with legacy status for now (might get deprecated/removed later)
|
||||
mnObj.pushKV("outpoint", node.mn_activeman->GetOutPoint().ToStringShort());
|
||||
mnObj.pushKV("service", node.mn_activeman->GetService().ToString());
|
||||
CDeterministicMNCPtr dmn = node.dmnman->GetListAtChainTip().GetMN(node.mn_activeman->GetProTxHash());
|
||||
if (dmn) {
|
||||
mnObj.pushKV("proTxHash", dmn->proTxHash.ToString());
|
||||
mnObj.pushKV("type", std::string(GetMnType(dmn->nType).description));
|
||||
|
@ -299,7 +299,7 @@ static UniValue quorum_dkgstatus(const JSONRPCRequest& request, CDeterministicMN
|
||||
const uint256 proTxHash = [&mn_activeman]() {
|
||||
if (!fMasternodeMode) return uint256();
|
||||
CHECK_NONFATAL(mn_activeman);
|
||||
return WITH_LOCK(mn_activeman->cs, return mn_activeman->GetProTxHash());
|
||||
return mn_activeman->GetProTxHash();
|
||||
}();
|
||||
|
||||
UniValue minableCommitments(UniValue::VARR);
|
||||
|
@ -219,8 +219,10 @@ void EnterCritical(const char* pszName, const char* pszFile, int nLine, MutexTyp
|
||||
}
|
||||
template void EnterCritical(const char*, const char*, int, Mutex*, bool);
|
||||
template void EnterCritical(const char*, const char*, int, RecursiveMutex*, bool);
|
||||
template void EnterCritical(const char*, const char*, int, SharedMutex*, bool);
|
||||
template void EnterCritical(const char*, const char*, int, std::mutex*, bool);
|
||||
template void EnterCritical(const char*, const char*, int, std::recursive_mutex*, bool);
|
||||
template void EnterCritical(const char*, const char*, int, std::shared_mutex*, bool);
|
||||
|
||||
void CheckLastCritical(void* cs, std::string& lockname, const char* guardname, const char* file, int line)
|
||||
{
|
||||
@ -287,6 +289,7 @@ void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine,
|
||||
}
|
||||
template void AssertLockHeldInternal(const char*, const char*, int, Mutex*);
|
||||
template void AssertLockHeldInternal(const char*, const char*, int, RecursiveMutex*);
|
||||
template void AssertLockHeldInternal(const char*, const char*, int, SharedMutex*);
|
||||
|
||||
void AssertLockNotHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
|
||||
{
|
||||
|
81
src/sync.h
81
src/sync.h
@ -11,6 +11,7 @@
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
@ -115,6 +116,21 @@ public:
|
||||
#endif // __clang__
|
||||
};
|
||||
|
||||
template <typename PARENT>
|
||||
class LOCKABLE SharedAnnotatedMixin : public AnnotatedMixin<PARENT>
|
||||
{
|
||||
public:
|
||||
bool try_shared_lock() SHARED_TRYLOCK_FUNCTION(true)
|
||||
{
|
||||
return PARENT::try_shared_lock();
|
||||
}
|
||||
void shared_lock() SHARED_LOCK_FUNCTION()
|
||||
{
|
||||
PARENT::shared_lock();
|
||||
}
|
||||
using SharedLock = std::shared_lock<PARENT>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapped mutex: supports recursive locking, but no waiting
|
||||
* TODO: We should move away from using the recursive lock by default.
|
||||
@ -123,6 +139,9 @@ using RecursiveMutex = AnnotatedMixin<std::recursive_mutex>;
|
||||
|
||||
/** Wrapped mutex: supports waiting but not recursive locking */
|
||||
typedef AnnotatedMixin<std::mutex> Mutex;
|
||||
/** Wrapped shared mutex: supports read locking via .shared_lock, exlusive locking via .lock;
|
||||
* does not support recursive locking */
|
||||
typedef SharedAnnotatedMixin<std::shared_mutex> SharedMutex;
|
||||
|
||||
/** Prints a lock contention to the log */
|
||||
void LockContention(const char* pszName, const char* pszFile, int nLine);
|
||||
@ -217,16 +236,77 @@ public:
|
||||
friend class reverse_lock;
|
||||
};
|
||||
|
||||
template <typename Mutex, typename Base = typename Mutex::SharedLock>
|
||||
class SCOPED_LOCKABLE SharedLock : public Base
|
||||
{
|
||||
private:
|
||||
void SharedEnter(const char* pszName, const char* pszFile, int nLine)
|
||||
{
|
||||
EnterCritical(pszName, pszFile, nLine, Base::mutex());
|
||||
#ifdef DEBUG_LOCKCONTENTION
|
||||
if (!Base::try_lock()) {
|
||||
PrintLockContention(pszName, pszFile, nLine);
|
||||
#endif
|
||||
Base::lock();
|
||||
#ifdef DEBUG_LOCKCONTENTION
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool TrySharedEnter(const char* pszName, const char* pszFile, int nLine)
|
||||
{
|
||||
EnterCritical(pszName, pszFile, nLine, Base::mutex(), true);
|
||||
if (Base::try_lock()) {
|
||||
return true;
|
||||
}
|
||||
LeaveCritical();
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
SharedLock(Mutex& mutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) SHARED_LOCK_FUNCTION(mutexIn) : Base(mutexIn, std::defer_lock)
|
||||
{
|
||||
if (fTry) {
|
||||
TrySharedEnter(pszName, pszFile, nLine);
|
||||
} else {
|
||||
SharedEnter(pszName, pszFile, nLine);
|
||||
}
|
||||
}
|
||||
|
||||
SharedLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false) SHARED_LOCK_FUNCTION(pmutexIn)
|
||||
{
|
||||
if (!pmutexIn) return;
|
||||
|
||||
*static_cast<Base*>(this) = Base(*pmutexIn, std::defer_lock);
|
||||
if (fTry) {
|
||||
TrySharedEnter(pszName, pszFile, nLine);
|
||||
} else {
|
||||
SharedEnter(pszName, pszFile, nLine);
|
||||
}
|
||||
}
|
||||
|
||||
~SharedLock() UNLOCK_FUNCTION()
|
||||
{
|
||||
if (Base::owns_lock()) {
|
||||
LeaveCritical();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define REVERSE_LOCK(g) typename std::decay<decltype(g)>::type::reverse_lock PASTE2(revlock, __COUNTER__)(g, #g, __FILE__, __LINE__)
|
||||
|
||||
template<typename MutexArg>
|
||||
using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;
|
||||
template<typename MutexArg>
|
||||
using ReadLock = SharedLock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;
|
||||
|
||||
#define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
|
||||
#define READ_LOCK(cs) ReadLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
|
||||
#define LOCK2(cs1, cs2) \
|
||||
DebugLock<decltype(cs1)> criticalblock1(cs1, #cs1, __FILE__, __LINE__); \
|
||||
DebugLock<decltype(cs2)> criticalblock2(cs2, #cs2, __FILE__, __LINE__);
|
||||
#define TRY_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
|
||||
#define TRY_READ_LOCK(cs, name) ReadLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__, true)
|
||||
#define WAIT_LOCK(cs, name) DebugLock<decltype(cs)> name(cs, #cs, __FILE__, __LINE__)
|
||||
|
||||
#define ENTER_CRITICAL_SECTION(cs) \
|
||||
@ -267,6 +347,7 @@ using DebugLock = UniqueLock<typename std::remove_reference<typename std::remove
|
||||
//! The above is detectable at compile-time with the -Wreturn-local-addr flag in
|
||||
//! gcc and the -Wreturn-stack-address flag in clang, both enabled by default.
|
||||
#define WITH_LOCK(cs, code) [&]() -> decltype(auto) { LOCK(cs); code; }()
|
||||
#define WITH_READ_LOCK(cs, code) [&]() -> decltype(auto) { READ_LOCK(cs); code; }()
|
||||
|
||||
class CSemaphore
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user