mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
refactor(coinjoin): remove CCriticalSection from coinjoin code, use mutexes instead (#4739)
* refactor: remove CCriticalSection from coinjoin code, use mutexes instead * refactor(coinjoin): more annotations * fix cs_coinjoin double-lock deadlock Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
This commit is contained in:
parent
43152b2b35
commit
407873e024
@ -99,9 +99,11 @@ void CCoinJoinClientQueueManager::ProcessMessage(CNode* pfrom, const std::string
|
||||
ranges::any_of(coinJoinClientManagers,
|
||||
[&dsq](const auto& pair){ return pair.second->MarkAlreadyJoinedQueueAsTried(dsq); });
|
||||
|
||||
TRY_LOCK(cs_vecqueue, lockRecv);
|
||||
if (!lockRecv) return;
|
||||
vecCoinJoinQueue.push_back(dsq);
|
||||
{
|
||||
TRY_LOCK(cs_vecqueue, lockRecv);
|
||||
if (!lockRecv) return;
|
||||
vecCoinJoinQueue.push_back(dsq);
|
||||
}
|
||||
dsq.Relay(connman);
|
||||
}
|
||||
|
||||
@ -124,6 +126,7 @@ void CCoinJoinClientManager::ProcessMessage(CNode* pfrom, const std::string& msg
|
||||
if (msg_type == NetMsgType::DSSTATUSUPDATE ||
|
||||
msg_type == NetMsgType::DSFINALTX ||
|
||||
msg_type == NetMsgType::DSCOMPLETE) {
|
||||
AssertLockNotHeld(cs_deqsessions);
|
||||
LOCK(cs_deqsessions);
|
||||
for (auto& session : deqSessions) {
|
||||
session.ProcessMessage(pfrom, msg_type, vRecv, connman, enable_bip61);
|
||||
@ -214,13 +217,14 @@ void CCoinJoinClientSession::ResetPool()
|
||||
txMyCollateral = CMutableTransaction();
|
||||
UnlockCoins();
|
||||
keyHolderStorage.ReturnAll();
|
||||
SetNull();
|
||||
WITH_LOCK(cs_coinjoin, SetNull());
|
||||
}
|
||||
|
||||
void CCoinJoinClientManager::ResetPool()
|
||||
{
|
||||
nCachedLastSuccessBlock = 0;
|
||||
vecMasternodesUsed.clear();
|
||||
AssertLockNotHeld(cs_deqsessions);
|
||||
LOCK(cs_deqsessions);
|
||||
for (auto& session : deqSessions) {
|
||||
session.ResetPool();
|
||||
@ -230,6 +234,7 @@ void CCoinJoinClientManager::ResetPool()
|
||||
|
||||
void CCoinJoinClientSession::SetNull()
|
||||
{
|
||||
AssertLockHeld(cs_coinjoin);
|
||||
// Client side
|
||||
mixingMasternode = nullptr;
|
||||
pendingDsaRequest = CPendingDsaRequest();
|
||||
@ -303,6 +308,7 @@ bilingual_str CCoinJoinClientManager::GetStatuses()
|
||||
bilingual_str strStatus;
|
||||
bool fWaitForBlock = WaitForAnotherBlock();
|
||||
|
||||
AssertLockNotHeld(cs_deqsessions);
|
||||
LOCK(cs_deqsessions);
|
||||
for (const auto& session : deqSessions) {
|
||||
strStatus = strStatus + session.GetStatus(fWaitForBlock) + Untranslated("; ");
|
||||
@ -314,6 +320,7 @@ std::string CCoinJoinClientManager::GetSessionDenoms()
|
||||
{
|
||||
std::string strSessionDenoms;
|
||||
|
||||
AssertLockNotHeld(cs_deqsessions);
|
||||
LOCK(cs_deqsessions);
|
||||
for (const auto& session : deqSessions) {
|
||||
strSessionDenoms += CCoinJoin::DenominationToString(session.nSessionDenom);
|
||||
@ -330,6 +337,7 @@ bool CCoinJoinClientSession::GetMixingMasternodeInfo(CDeterministicMNCPtr& ret)
|
||||
|
||||
bool CCoinJoinClientManager::GetMixingMasternodesInfo(std::vector<CDeterministicMNCPtr>& vecDmnsRet) const
|
||||
{
|
||||
AssertLockNotHeld(cs_deqsessions);
|
||||
LOCK(cs_deqsessions);
|
||||
for (const auto& session : deqSessions) {
|
||||
CDeterministicMNCPtr dmn;
|
||||
@ -353,7 +361,7 @@ bool CCoinJoinClientSession::CheckTimeout()
|
||||
if (GetTime() - nTimeLastSuccessfulStep >= 10) {
|
||||
// reset after being in POOL_STATE_ERROR for 10 or more seconds
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::%s -- resetting session %d\n", __func__, nSessionID);
|
||||
SetNull();
|
||||
WITH_LOCK(cs_coinjoin, SetNull());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -381,6 +389,7 @@ bool CCoinJoinClientSession::CheckTimeout()
|
||||
//
|
||||
void CCoinJoinClientManager::CheckTimeout()
|
||||
{
|
||||
AssertLockNotHeld(cs_deqsessions);
|
||||
if (fMasternodeMode) return;
|
||||
|
||||
if (!CCoinJoinClientOptions::IsEnabled() || !IsMixing()) return;
|
||||
@ -414,14 +423,14 @@ bool CCoinJoinClientSession::SendDenominate(const std::vector<std::pair<CTxDSIn,
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::SendDenominate -- No Masternode has been selected yet.\n");
|
||||
UnlockCoins();
|
||||
keyHolderStorage.ReturnAll();
|
||||
SetNull();
|
||||
WITH_LOCK(cs_coinjoin, SetNull());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CheckDiskSpace(GetDataDir())) {
|
||||
UnlockCoins();
|
||||
keyHolderStorage.ReturnAll();
|
||||
SetNull();
|
||||
WITH_LOCK(cs_coinjoin, SetNull());
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::SendDenominate -- Not enough disk space.\n");
|
||||
return false;
|
||||
}
|
||||
@ -634,7 +643,7 @@ void CCoinJoinClientSession::CompletedTransaction(PoolMessage nMessageID)
|
||||
keyHolderStorage.ReturnAll();
|
||||
}
|
||||
UnlockCoins();
|
||||
SetNull();
|
||||
WITH_LOCK(cs_coinjoin, SetNull());
|
||||
strLastMessage = CCoinJoin::GetMessageByID(nMessageID);
|
||||
}
|
||||
|
||||
@ -931,6 +940,7 @@ bool CCoinJoinClientManager::DoAutomaticDenominating(CConnman& connman, bool fDr
|
||||
}
|
||||
|
||||
bool fResult = true;
|
||||
AssertLockNotHeld(cs_deqsessions);
|
||||
LOCK(cs_deqsessions);
|
||||
if ((int)deqSessions.size() < CCoinJoinClientOptions::GetSessions()) {
|
||||
deqSessions.emplace_back(mixingWallet);
|
||||
@ -1152,7 +1162,7 @@ bool CCoinJoinClientSession::ProcessPendingDsaRequest(CConnman& connman)
|
||||
pendingDsaRequest = CPendingDsaRequest();
|
||||
} else if (pendingDsaRequest.IsExpired()) {
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinClientSession::%s -- failed to connect to %s\n", __func__, pendingDsaRequest.GetAddr().ToString());
|
||||
SetNull();
|
||||
WITH_LOCK(cs_coinjoin, SetNull());
|
||||
}
|
||||
|
||||
return fDone;
|
||||
@ -1160,6 +1170,7 @@ bool CCoinJoinClientSession::ProcessPendingDsaRequest(CConnman& connman)
|
||||
|
||||
void CCoinJoinClientManager::ProcessPendingDsaRequest(CConnman& connman)
|
||||
{
|
||||
AssertLockNotHeld(cs_deqsessions);
|
||||
LOCK(cs_deqsessions);
|
||||
for (auto& session : deqSessions) {
|
||||
if (session.ProcessPendingDsaRequest(connman)) {
|
||||
@ -1170,6 +1181,7 @@ void CCoinJoinClientManager::ProcessPendingDsaRequest(CConnman& connman)
|
||||
|
||||
bool CCoinJoinClientManager::TrySubmitDenominate(const CService& mnAddr, CConnman& connman)
|
||||
{
|
||||
AssertLockNotHeld(cs_deqsessions);
|
||||
LOCK(cs_deqsessions);
|
||||
for (auto& session : deqSessions) {
|
||||
CDeterministicMNCPtr mnMixing;
|
||||
@ -1183,6 +1195,7 @@ bool CCoinJoinClientManager::TrySubmitDenominate(const CService& mnAddr, CConnma
|
||||
|
||||
bool CCoinJoinClientManager::MarkAlreadyJoinedQueueAsTried(CCoinJoinQueue& dsq) const
|
||||
{
|
||||
AssertLockNotHeld(cs_deqsessions);
|
||||
LOCK(cs_deqsessions);
|
||||
for (const auto& session : deqSessions) {
|
||||
CDeterministicMNCPtr mnMixing;
|
||||
@ -1818,6 +1831,7 @@ void CCoinJoinClientManager::GetJsonInfo(UniValue& obj) const
|
||||
obj.pushKV("running", IsMixing());
|
||||
|
||||
UniValue arrSessions(UniValue::VARR);
|
||||
AssertLockNotHeld(cs_deqsessions);
|
||||
LOCK(cs_deqsessions);
|
||||
for (const auto& session : deqSessions) {
|
||||
if (session.GetState() != POOL_STATE_IDLE) {
|
||||
|
@ -101,7 +101,7 @@ private:
|
||||
/// step 1: prepare denominated inputs and outputs
|
||||
bool PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, const std::vector<CTxDSIn>& vecTxDSIn, std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsRet, bool fDryRun = false);
|
||||
/// step 2: send denominated inputs and outputs prepared in step 1
|
||||
bool SendDenominate(const std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsIn, CConnman& connman);
|
||||
bool SendDenominate(const std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsIn, CConnman& connman) LOCKS_EXCLUDED(cs_coinjoin);
|
||||
|
||||
/// Process Masternode updates about the progress of mixing
|
||||
void ProcessPoolStateUpdate(CCoinJoinStatusUpdate psssup);
|
||||
@ -111,11 +111,11 @@ private:
|
||||
void CompletedTransaction(PoolMessage nMessageID);
|
||||
|
||||
/// As a client, check and sign the final transaction
|
||||
bool SignFinalTransaction(const CTransaction& finalTransactionNew, CNode* pnode, CConnman& connman);
|
||||
bool SignFinalTransaction(const CTransaction& finalTransactionNew, CNode* pnode, CConnman& connman) LOCKS_EXCLUDED(cs_coinjoin);
|
||||
|
||||
void RelayIn(const CCoinJoinEntry& entry, CConnman& connman) const;
|
||||
|
||||
void SetNull();
|
||||
void SetNull() EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin);
|
||||
|
||||
public:
|
||||
explicit CCoinJoinClientSession(CWallet& pwallet) :
|
||||
@ -127,14 +127,14 @@ public:
|
||||
|
||||
void UnlockCoins();
|
||||
|
||||
void ResetPool();
|
||||
void ResetPool() LOCKS_EXCLUDED(cs_coinjoin);
|
||||
|
||||
bilingual_str GetStatus(bool fWaitForBlock) const;
|
||||
|
||||
bool GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const;
|
||||
|
||||
/// Passively run mixing in the background according to the configuration in settings
|
||||
bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false);
|
||||
bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false) LOCKS_EXCLUDED(cs_coinjoin);
|
||||
|
||||
/// As a client, submit part of a future mixing transaction to a Masternode to start the process
|
||||
bool SubmitDenominate(CConnman& connman);
|
||||
@ -151,7 +151,7 @@ public:
|
||||
class CCoinJoinClientQueueManager : public CCoinJoinBaseManager
|
||||
{
|
||||
public:
|
||||
void ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
|
||||
void ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61) LOCKS_EXCLUDED(cs_vecqueue);
|
||||
|
||||
void DoMaintenance();
|
||||
};
|
||||
@ -164,7 +164,7 @@ private:
|
||||
// Keep track of the used Masternodes
|
||||
std::vector<COutPoint> vecMasternodesUsed;
|
||||
|
||||
mutable CCriticalSection cs_deqsessions;
|
||||
mutable Mutex cs_deqsessions;
|
||||
// TODO: or map<denom, CCoinJoinClientSession> ??
|
||||
std::deque<CCoinJoinClientSession> deqSessions GUARDED_BY(cs_deqsessions);
|
||||
|
||||
@ -195,27 +195,27 @@ public:
|
||||
explicit CCoinJoinClientManager(CWallet& wallet) :
|
||||
mixingWallet(wallet) {}
|
||||
|
||||
void ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
|
||||
void ProcessMessage(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61) LOCKS_EXCLUDED(cs_deqsessions);
|
||||
|
||||
bool StartMixing();
|
||||
void StopMixing();
|
||||
bool IsMixing() const;
|
||||
void ResetPool();
|
||||
void ResetPool() LOCKS_EXCLUDED(cs_deqsessions);
|
||||
|
||||
bilingual_str GetStatuses();
|
||||
std::string GetSessionDenoms();
|
||||
bilingual_str GetStatuses() LOCKS_EXCLUDED(cs_deqsessions);
|
||||
std::string GetSessionDenoms() LOCKS_EXCLUDED(cs_deqsessions);
|
||||
|
||||
bool GetMixingMasternodesInfo(std::vector<CDeterministicMNCPtr>& vecDmnsRet) const;
|
||||
bool GetMixingMasternodesInfo(std::vector<CDeterministicMNCPtr>& vecDmnsRet) const LOCKS_EXCLUDED(cs_deqsessions);
|
||||
|
||||
/// Passively run mixing in the background according to the configuration in settings
|
||||
bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false);
|
||||
bool DoAutomaticDenominating(CConnman& connman, bool fDryRun = false) LOCKS_EXCLUDED(cs_deqsessions);
|
||||
|
||||
bool TrySubmitDenominate(const CService& mnAddr, CConnman& connman);
|
||||
bool MarkAlreadyJoinedQueueAsTried(CCoinJoinQueue& dsq) const;
|
||||
bool TrySubmitDenominate(const CService& mnAddr, CConnman& connman) LOCKS_EXCLUDED(cs_deqsessions);
|
||||
bool MarkAlreadyJoinedQueueAsTried(CCoinJoinQueue& dsq) const LOCKS_EXCLUDED(cs_deqsessions);
|
||||
|
||||
void CheckTimeout();
|
||||
void CheckTimeout() LOCKS_EXCLUDED(cs_deqsessions);
|
||||
|
||||
void ProcessPendingDsaRequest(CConnman& connman);
|
||||
void ProcessPendingDsaRequest(CConnman& connman) LOCKS_EXCLUDED(cs_deqsessions);
|
||||
|
||||
void AddUsedMasternode(const COutPoint& outpointMn);
|
||||
CDeterministicMNCPtr GetRandomNotUsedMasternode();
|
||||
@ -226,7 +226,7 @@ public:
|
||||
|
||||
void DoMaintenance(CConnman& connman);
|
||||
|
||||
void GetJsonInfo(UniValue& obj) const;
|
||||
void GetJsonInfo(UniValue& obj) const LOCKS_EXCLUDED(cs_deqsessions);
|
||||
};
|
||||
|
||||
|
||||
|
@ -145,7 +145,7 @@ bool CCoinJoinBroadcastTx::IsValidStructure() const
|
||||
void CCoinJoinBaseSession::SetNull()
|
||||
{
|
||||
// Both sides
|
||||
LOCK(cs_coinjoin);
|
||||
AssertLockHeld(cs_coinjoin);
|
||||
nState = POOL_STATE_IDLE;
|
||||
nSessionID = 0;
|
||||
nSessionDenom = 0;
|
||||
@ -301,7 +301,7 @@ bool CCoinJoinBaseSession::IsValidInOuts(const std::vector<CTxIn>& vin, const st
|
||||
}
|
||||
|
||||
// Definitions for static data members
|
||||
CCriticalSection CCoinJoin::cs_mapdstx;
|
||||
Mutex CCoinJoin::cs_mapdstx;
|
||||
std::map<uint256, CCoinJoinBroadcastTx> CCoinJoin::mapDSTX GUARDED_BY(CCoinJoin::cs_mapdstx);
|
||||
|
||||
// check to make sure the collateral provided by the client is valid
|
||||
@ -429,12 +429,14 @@ bilingual_str CCoinJoin::GetMessageByID(PoolMessage nMessageID)
|
||||
|
||||
void CCoinJoin::AddDSTX(const CCoinJoinBroadcastTx& dstx)
|
||||
{
|
||||
AssertLockNotHeld(cs_mapdstx);
|
||||
LOCK(cs_mapdstx);
|
||||
mapDSTX.insert(std::make_pair(dstx.tx->GetHash(), dstx));
|
||||
}
|
||||
|
||||
CCoinJoinBroadcastTx CCoinJoin::GetDSTX(const uint256& hash)
|
||||
{
|
||||
AssertLockNotHeld(cs_mapdstx);
|
||||
LOCK(cs_mapdstx);
|
||||
auto it = mapDSTX.find(hash);
|
||||
return (it == mapDSTX.end()) ? CCoinJoinBroadcastTx() : it->second;
|
||||
@ -442,6 +444,7 @@ CCoinJoinBroadcastTx CCoinJoin::GetDSTX(const uint256& hash)
|
||||
|
||||
void CCoinJoin::CheckDSTXes(const CBlockIndex* pindex)
|
||||
{
|
||||
AssertLockNotHeld(cs_mapdstx);
|
||||
LOCK(cs_mapdstx);
|
||||
auto it = mapDSTX.begin();
|
||||
while (it != mapDSTX.end()) {
|
||||
@ -483,12 +486,14 @@ void CCoinJoin::UpdateDSTXConfirmedHeight(const CTransactionRef& tx, int nHeight
|
||||
|
||||
void CCoinJoin::TransactionAddedToMempool(const CTransactionRef& tx)
|
||||
{
|
||||
AssertLockNotHeld(cs_mapdstx);
|
||||
LOCK(cs_mapdstx);
|
||||
UpdateDSTXConfirmedHeight(tx, -1);
|
||||
}
|
||||
|
||||
void CCoinJoin::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted)
|
||||
{
|
||||
AssertLockNotHeld(cs_mapdstx);
|
||||
LOCK(cs_mapdstx);
|
||||
for (const auto& tx : vtxConflicted) {
|
||||
UpdateDSTXConfirmedHeight(tx, -1);
|
||||
@ -501,6 +506,7 @@ void CCoinJoin::BlockConnected(const std::shared_ptr<const CBlock>& pblock, cons
|
||||
|
||||
void CCoinJoin::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex*)
|
||||
{
|
||||
AssertLockNotHeld(cs_mapdstx);
|
||||
LOCK(cs_mapdstx);
|
||||
for (const auto& tx : pblock->vtx) {
|
||||
UpdateDSTXConfirmedHeight(tx, -1);
|
||||
|
@ -308,7 +308,7 @@ public:
|
||||
class CCoinJoinBaseSession
|
||||
{
|
||||
protected:
|
||||
mutable CCriticalSection cs_coinjoin;
|
||||
mutable Mutex cs_coinjoin;
|
||||
|
||||
std::vector<CCoinJoinEntry> vecEntries GUARDED_BY(cs_coinjoin); // Masternode/clients entries
|
||||
|
||||
@ -319,7 +319,7 @@ protected:
|
||||
|
||||
CMutableTransaction finalMutableTransaction GUARDED_BY(cs_coinjoin); // the finalized transaction ready for signing
|
||||
|
||||
void SetNull();
|
||||
void SetNull() EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin);
|
||||
|
||||
bool IsValidInOuts(const std::vector<CTxIn>& vin, const std::vector<CTxOut>& vout, PoolMessage& nMessageIDRet, bool* fConsumeCollateralRet) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||
|
||||
@ -331,26 +331,27 @@ public:
|
||||
int GetState() const { return nState; }
|
||||
std::string GetStateString() const;
|
||||
|
||||
int GetEntriesCount() const { LOCK(cs_coinjoin); return vecEntries.size(); }
|
||||
int GetEntriesCount() const LOCKS_EXCLUDED(cs_coinjoin) { LOCK(cs_coinjoin); return vecEntries.size(); }
|
||||
int GetEntriesCountLocked() const EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin) { return vecEntries.size(); }
|
||||
};
|
||||
|
||||
// base class
|
||||
class CCoinJoinBaseManager
|
||||
{
|
||||
protected:
|
||||
mutable CCriticalSection cs_vecqueue;
|
||||
mutable Mutex cs_vecqueue;
|
||||
|
||||
// The current mixing sessions in progress on the network
|
||||
std::vector<CCoinJoinQueue> vecCoinJoinQueue GUARDED_BY(cs_vecqueue);
|
||||
|
||||
void SetNull();
|
||||
void CheckQueue();
|
||||
void SetNull() LOCKS_EXCLUDED(cs_vecqueue);
|
||||
void CheckQueue() LOCKS_EXCLUDED(cs_vecqueue);
|
||||
|
||||
public:
|
||||
CCoinJoinBaseManager() = default;
|
||||
|
||||
int GetQueueSize() const { LOCK(cs_vecqueue); return vecCoinJoinQueue.size(); }
|
||||
bool GetQueueItemAndTry(CCoinJoinQueue& dsqRet);
|
||||
int GetQueueSize() const LOCKS_EXCLUDED(cs_vecqueue) { LOCK(cs_vecqueue); return vecCoinJoinQueue.size(); }
|
||||
bool GetQueueItemAndTry(CCoinJoinQueue& dsqRet) LOCKS_EXCLUDED(cs_vecqueue);
|
||||
};
|
||||
|
||||
// helper class
|
||||
@ -374,9 +375,9 @@ private:
|
||||
|
||||
static std::map<uint256, CCoinJoinBroadcastTx> mapDSTX;
|
||||
|
||||
static CCriticalSection cs_mapdstx;
|
||||
static Mutex cs_mapdstx;
|
||||
|
||||
static void CheckDSTXes(const CBlockIndex* pindex);
|
||||
static void CheckDSTXes(const CBlockIndex* pindex) LOCKS_EXCLUDED(cs_mapdstx);
|
||||
|
||||
public:
|
||||
static constexpr std::array<CAmount, 5> GetStandardDenominations() { return vecStandardDenominations; }
|
||||
@ -476,16 +477,16 @@ public:
|
||||
}
|
||||
|
||||
|
||||
static void AddDSTX(const CCoinJoinBroadcastTx& dstx);
|
||||
static CCoinJoinBroadcastTx GetDSTX(const uint256& hash);
|
||||
static void AddDSTX(const CCoinJoinBroadcastTx& dstx) LOCKS_EXCLUDED(cs_mapdstx);
|
||||
static CCoinJoinBroadcastTx GetDSTX(const uint256& hash) LOCKS_EXCLUDED(cs_mapdstx);
|
||||
|
||||
static void UpdatedBlockTip(const CBlockIndex* pindex);
|
||||
static void NotifyChainLock(const CBlockIndex* pindex);
|
||||
|
||||
static void UpdateDSTXConfirmedHeight(const CTransactionRef& tx, int nHeight);
|
||||
static void TransactionAddedToMempool(const CTransactionRef& tx);
|
||||
static void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted);
|
||||
static void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex*);
|
||||
static void TransactionAddedToMempool(const CTransactionRef& tx) LOCKS_EXCLUDED(cs_mapdstx);
|
||||
static void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted) LOCKS_EXCLUDED(cs_mapdstx);
|
||||
static void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex*) LOCKS_EXCLUDED(cs_mapdstx);
|
||||
|
||||
};
|
||||
|
||||
|
@ -186,6 +186,7 @@ void CCoinJoinServer::ProcessDSVIN(CNode* pfrom, const std::string& msg_type, CD
|
||||
if (AddEntry(connman, entry, nMessageID)) {
|
||||
PushStatus(pfrom, STATUS_ACCEPTED, nMessageID, connman);
|
||||
CheckPool(connman);
|
||||
LOCK(cs_coinjoin);
|
||||
RelayStatus(STATUS_ACCEPTED, connman);
|
||||
} else {
|
||||
PushStatus(pfrom, STATUS_REJECTED, nMessageID, connman);
|
||||
@ -206,6 +207,7 @@ void CCoinJoinServer::ProcessDSSIGNFINALTX(CNode* pfrom, const std::string& msg_
|
||||
nTxInIndex++;
|
||||
if (!AddScriptSig(txin)) {
|
||||
LogPrint(BCLog::COINJOIN, "DSSIGNFINALTX -- AddScriptSig() failed at %d/%d, session: %d\n", nTxInIndex, nTxInsCount, nSessionID);
|
||||
LOCK(cs_coinjoin);
|
||||
RelayStatus(STATUS_REJECTED, connman);
|
||||
return;
|
||||
}
|
||||
@ -217,6 +219,7 @@ void CCoinJoinServer::ProcessDSSIGNFINALTX(CNode* pfrom, const std::string& msg_
|
||||
|
||||
void CCoinJoinServer::SetNull()
|
||||
{
|
||||
AssertLockHeld(cs_coinjoin);
|
||||
// MN side
|
||||
vecSessionCollaterals.clear();
|
||||
|
||||
@ -261,6 +264,7 @@ void CCoinJoinServer::CheckPool(CConnman& connman)
|
||||
|
||||
void CCoinJoinServer::CreateFinalTransaction(CConnman& connman)
|
||||
{
|
||||
AssertLockNotHeld(cs_coinjoin);
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CreateFinalTransaction -- FINALIZE TRANSACTIONS\n");
|
||||
|
||||
LOCK(cs_coinjoin);
|
||||
@ -268,7 +272,7 @@ void CCoinJoinServer::CreateFinalTransaction(CConnman& connman)
|
||||
CMutableTransaction txNew;
|
||||
|
||||
// make our new transaction
|
||||
for (int i = 0; i < GetEntriesCount(); i++) {
|
||||
for (int i = 0; i < GetEntriesCountLocked(); i++) {
|
||||
for (const auto& txout : vecEntries[i].vecTxOut) {
|
||||
txNew.vout.push_back(txout);
|
||||
}
|
||||
@ -290,6 +294,7 @@ void CCoinJoinServer::CreateFinalTransaction(CConnman& connman)
|
||||
|
||||
void CCoinJoinServer::CommitFinalTransaction(CConnman& connman)
|
||||
{
|
||||
AssertLockNotHeld(cs_coinjoin);
|
||||
if (!fMasternodeMode) return; // check and relay final tx only on masternode
|
||||
|
||||
CTransactionRef finalTransaction = WITH_LOCK(cs_coinjoin, return MakeTransactionRef(finalMutableTransaction));
|
||||
@ -304,7 +309,7 @@ void CCoinJoinServer::CommitFinalTransaction(CConnman& connman)
|
||||
mempool.PrioritiseTransaction(hashTx, 0.1 * COIN);
|
||||
if (!lockMain || !AcceptToMemoryPool(mempool, validationState, finalTransaction, nullptr /* pfMissingInputs */, false /* bypass_limits */, DEFAULT_MAX_RAW_TX_FEE /* nAbsurdFee */)) {
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n");
|
||||
SetNull();
|
||||
WITH_LOCK(cs_coinjoin, SetNull());
|
||||
// not much we can do in this case, just notify clients
|
||||
RelayCompletedTransaction(ERR_INVALID_TX, connman);
|
||||
return;
|
||||
@ -333,7 +338,7 @@ void CCoinJoinServer::CommitFinalTransaction(CConnman& connman)
|
||||
|
||||
// Reset
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CommitFinalTransaction -- COMPLETED -- RESETTING\n");
|
||||
SetNull();
|
||||
WITH_LOCK(cs_coinjoin, SetNull());
|
||||
}
|
||||
|
||||
//
|
||||
@ -350,6 +355,7 @@ void CCoinJoinServer::CommitFinalTransaction(CConnman& connman)
|
||||
//
|
||||
void CCoinJoinServer::ChargeFees(CConnman& connman) const
|
||||
{
|
||||
AssertLockNotHeld(cs_coinjoin);
|
||||
if (!fMasternodeMode) return;
|
||||
|
||||
//we don't need to charge collateral for every offence.
|
||||
@ -465,7 +471,7 @@ void CCoinJoinServer::CheckTimeout(CConnman& connman)
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::CheckTimeout -- %s timed out -- resetting\n",
|
||||
(nState == POOL_STATE_SIGNING) ? "Signing" : "Session");
|
||||
ChargeFees(connman);
|
||||
SetNull();
|
||||
WITH_LOCK(cs_coinjoin, SetNull());
|
||||
}
|
||||
|
||||
/*
|
||||
@ -491,6 +497,7 @@ void CCoinJoinServer::CheckForCompleteQueue(CConnman& connman)
|
||||
// Check to make sure a given input matches an input in the pool and its scriptSig is valid
|
||||
bool CCoinJoinServer::IsInputScriptSigValid(const CTxIn& txin) const
|
||||
{
|
||||
AssertLockHeld(cs_coinjoin);
|
||||
CMutableTransaction txNew;
|
||||
txNew.vin.clear();
|
||||
txNew.vout.clear();
|
||||
@ -499,7 +506,6 @@ bool CCoinJoinServer::IsInputScriptSigValid(const CTxIn& txin) const
|
||||
CScript sigPubKey = CScript();
|
||||
|
||||
{
|
||||
LOCK(cs_coinjoin);
|
||||
int i = 0;
|
||||
for (const auto &entry: vecEntries) {
|
||||
for (const auto &txout: entry.vecTxOut) {
|
||||
@ -538,6 +544,7 @@ bool CCoinJoinServer::IsInputScriptSigValid(const CTxIn& txin) const
|
||||
//
|
||||
bool CCoinJoinServer::AddEntry(CConnman& connman, const CCoinJoinEntry& entry, PoolMessage& nMessageIDRet)
|
||||
{
|
||||
AssertLockNotHeld(cs_coinjoin);
|
||||
if (!fMasternodeMode) return false;
|
||||
|
||||
if (size_t(GetEntriesCount()) >= vecSessionCollaterals.size()) {
|
||||
@ -600,6 +607,7 @@ bool CCoinJoinServer::AddEntry(CConnman& connman, const CCoinJoinEntry& entry, P
|
||||
|
||||
bool CCoinJoinServer::AddScriptSig(const CTxIn& txinNew)
|
||||
{
|
||||
AssertLockNotHeld(cs_coinjoin);
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::AddScriptSig -- scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0, 24));
|
||||
|
||||
LOCK(cs_coinjoin);
|
||||
@ -624,7 +632,7 @@ bool CCoinJoinServer::AddScriptSig(const CTxIn& txinNew)
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::AddScriptSig -- adding to finalMutableTransaction, scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0, 24));
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < GetEntriesCount(); i++) {
|
||||
for (int i = 0; i < GetEntriesCountLocked(); i++) {
|
||||
if (vecEntries[i].AddScriptSig(txinNew)) {
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::AddScriptSig -- adding to entries, scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0, 24));
|
||||
return true;
|
||||
@ -638,6 +646,7 @@ bool CCoinJoinServer::AddScriptSig(const CTxIn& txinNew)
|
||||
// Check to make sure everything is signed
|
||||
bool CCoinJoinServer::IsSignaturesComplete() const
|
||||
{
|
||||
AssertLockNotHeld(cs_coinjoin);
|
||||
LOCK(cs_coinjoin);
|
||||
|
||||
return ranges::all_of(vecEntries, [](const auto& entry){
|
||||
@ -757,11 +766,11 @@ bool CCoinJoinServer::IsSessionReady() const
|
||||
|
||||
void CCoinJoinServer::RelayFinalTransaction(const CTransaction& txFinal, CConnman& connman)
|
||||
{
|
||||
AssertLockHeld(cs_coinjoin);
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- nSessionID: %d nSessionDenom: %d (%s)\n",
|
||||
__func__, nSessionID, nSessionDenom, CCoinJoin::DenominationToString(nSessionDenom));
|
||||
|
||||
// final mixing tx with empty signatures should be relayed to mixing participants only
|
||||
LOCK(cs_coinjoin);
|
||||
for (const auto& entry : vecEntries) {
|
||||
bool fOk = connman.ForNode(entry.addr, [&txFinal, &connman, this](CNode* pnode) {
|
||||
CNetMsgMaker msgMaker(pnode->GetSendVersion());
|
||||
@ -785,9 +794,9 @@ void CCoinJoinServer::PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, P
|
||||
|
||||
void CCoinJoinServer::RelayStatus(PoolStatusUpdate nStatusUpdate, CConnman& connman, PoolMessage nMessageID)
|
||||
{
|
||||
AssertLockHeld(cs_coinjoin);
|
||||
unsigned int nDisconnected{};
|
||||
// status updates should be relayed to mixing participants only
|
||||
LOCK(cs_coinjoin);
|
||||
for (const auto& entry : vecEntries) {
|
||||
// make sure everyone is still connected
|
||||
bool fOk = connman.ForNode(entry.addr, [&nStatusUpdate, &nMessageID, &connman, this](CNode* pnode) {
|
||||
@ -822,6 +831,7 @@ void CCoinJoinServer::RelayStatus(PoolStatusUpdate nStatusUpdate, CConnman& conn
|
||||
|
||||
void CCoinJoinServer::RelayCompletedTransaction(PoolMessage nMessageID, CConnman& connman)
|
||||
{
|
||||
AssertLockNotHeld(cs_coinjoin);
|
||||
LogPrint(BCLog::COINJOIN, "CCoinJoinServer::%s -- nSessionID: %d nSessionDenom: %d (%s)\n",
|
||||
__func__, nSessionID, nSessionDenom, CCoinJoin::DenominationToString(nSessionDenom));
|
||||
|
||||
|
@ -26,12 +26,12 @@ private:
|
||||
bool fUnitTest;
|
||||
|
||||
/// Add a clients entry to the pool
|
||||
bool AddEntry(CConnman& connman, const CCoinJoinEntry& entry, PoolMessage& nMessageIDRet);
|
||||
bool AddEntry(CConnman& connman, const CCoinJoinEntry& entry, PoolMessage& nMessageIDRet) LOCKS_EXCLUDED(cs_coinjoin);
|
||||
/// Add signature to a txin
|
||||
bool AddScriptSig(const CTxIn& txin);
|
||||
bool AddScriptSig(const CTxIn& txin) LOCKS_EXCLUDED(cs_coinjoin);
|
||||
|
||||
/// Charge fees to bad actors (Charge clients a fee if they're abusive)
|
||||
void ChargeFees(CConnman& connman) const;
|
||||
void ChargeFees(CConnman& connman) const LOCKS_EXCLUDED(cs_coinjoin);
|
||||
/// Rarely charge fees to pay miners
|
||||
void ChargeRandomFees(CConnman& connman) const;
|
||||
/// Consume collateral in cases when peer misbehaved
|
||||
@ -40,36 +40,36 @@ private:
|
||||
/// Check for process
|
||||
void CheckPool(CConnman& connman);
|
||||
|
||||
void CreateFinalTransaction(CConnman& connman);
|
||||
void CommitFinalTransaction(CConnman& connman);
|
||||
void CreateFinalTransaction(CConnman& connman) LOCKS_EXCLUDED(cs_coinjoin);
|
||||
void CommitFinalTransaction(CConnman& connman) LOCKS_EXCLUDED(cs_coinjoin);
|
||||
|
||||
/// Is this nDenom and txCollateral acceptable?
|
||||
bool IsAcceptableDSA(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet) const;
|
||||
bool CreateNewSession(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet, CConnman& connman);
|
||||
bool CreateNewSession(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet, CConnman& connman) LOCKS_EXCLUDED(cs_vecqueue);
|
||||
bool AddUserToExistingSession(const CCoinJoinAccept& dsa, PoolMessage& nMessageIDRet);
|
||||
/// Do we have enough users to take entries?
|
||||
bool IsSessionReady() const;
|
||||
|
||||
/// Check that all inputs are signed. (Are all inputs signed?)
|
||||
bool IsSignaturesComplete() const;
|
||||
bool IsSignaturesComplete() const LOCKS_EXCLUDED(cs_coinjoin);
|
||||
/// Check to make sure a given input matches an input in the pool and its scriptSig is valid
|
||||
bool IsInputScriptSigValid(const CTxIn& txin) const;
|
||||
bool IsInputScriptSigValid(const CTxIn& txin) const EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin);
|
||||
|
||||
// Set the 'state' value, with some logging and capturing when the state changed
|
||||
void SetState(PoolState nStateNew);
|
||||
|
||||
/// Relay mixing Messages
|
||||
void RelayFinalTransaction(const CTransaction& txFinal, CConnman& connman);
|
||||
void RelayFinalTransaction(const CTransaction& txFinal, CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin);
|
||||
void PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, CConnman& connman) const;
|
||||
void RelayStatus(PoolStatusUpdate nStatusUpdate, CConnman& connman, PoolMessage nMessageID = MSG_NOERR);
|
||||
void RelayCompletedTransaction(PoolMessage nMessageID, CConnman& connman);
|
||||
void RelayStatus(PoolStatusUpdate nStatusUpdate, CConnman& connman, PoolMessage nMessageID = MSG_NOERR) EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin);
|
||||
void RelayCompletedTransaction(PoolMessage nMessageID, CConnman& connman) LOCKS_EXCLUDED(cs_coinjoin);
|
||||
|
||||
void ProcessDSACCEPT(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
|
||||
void ProcessDSQUEUE(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
|
||||
void ProcessDSVIN(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
|
||||
void ProcessDSSIGNFINALTX(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61);
|
||||
void ProcessDSACCEPT(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61) LOCKS_EXCLUDED(cs_vecqueue);
|
||||
void ProcessDSQUEUE(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61) LOCKS_EXCLUDED(cs_vecqueue);
|
||||
void ProcessDSVIN(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61) LOCKS_EXCLUDED(cs_coinjoin);
|
||||
void ProcessDSSIGNFINALTX(CNode* pfrom, const std::string& msg_type, CDataStream& vRecv, CConnman& connman, bool enable_bip61) LOCKS_EXCLUDED(cs_coinjoin);
|
||||
|
||||
void SetNull();
|
||||
void SetNull() EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin);
|
||||
|
||||
public:
|
||||
CCoinJoinServer() :
|
||||
|
@ -29,13 +29,13 @@ public:
|
||||
class CKeyHolderStorage
|
||||
{
|
||||
private:
|
||||
mutable CCriticalSection cs_storage;
|
||||
mutable Mutex cs_storage;
|
||||
std::vector<std::unique_ptr<CKeyHolder> > storage GUARDED_BY(cs_storage);
|
||||
|
||||
public:
|
||||
CScript AddKey(CWallet* pwalletIn);
|
||||
void KeepAll();
|
||||
void ReturnAll();
|
||||
CScript AddKey(CWallet* pwalletIn) LOCKS_EXCLUDED(cs_storage);
|
||||
void KeepAll() LOCKS_EXCLUDED(cs_storage);
|
||||
void ReturnAll() LOCKS_EXCLUDED(cs_storage);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -93,7 +93,7 @@ class CTransactionBuilder
|
||||
/// Call KeepKey for all keys in destructor if fKeepKeys is true, call ReturnKey for all key if its false.
|
||||
bool fKeepKeys{false};
|
||||
/// Protect vecOutputs
|
||||
mutable CCriticalSection cs_outputs;
|
||||
mutable Mutex cs_outputs;
|
||||
/// Contains all outputs already added to the transaction
|
||||
std::vector<std::unique_ptr<CTransactionBuilderOutput>> vecOutputs GUARDED_BY(cs_outputs);
|
||||
/// Needed by CTransactionBuilderOutput::UpdateAmount to lock cs_outputs
|
||||
@ -107,7 +107,7 @@ public:
|
||||
/// Check if its possible to add multiple outputs as vector of amounts. Returns true if its possible to add all of them and false if not.
|
||||
bool CouldAddOutputs(const std::vector<CAmount>& vecOutputAmounts) const;
|
||||
/// Add an output with the amount nAmount. Returns a pointer to the output if it could be added and nullptr if not due to insufficient amount left.
|
||||
CTransactionBuilderOutput* AddOutput(CAmount nAmountOutput = 0);
|
||||
CTransactionBuilderOutput* AddOutput(CAmount nAmountOutput = 0) LOCKS_EXCLUDED(cs_outputs);
|
||||
/// Get amount we had available when we started
|
||||
CAmount GetAmountInitial() const { return tallyItem.nAmount; }
|
||||
/// Get the amount currently left to add more outputs. Does respect fees.
|
||||
@ -117,25 +117,25 @@ public:
|
||||
/// Get the total number of added outputs
|
||||
int CountOutputs() const { LOCK(cs_outputs); return vecOutputs.size(); }
|
||||
/// Create and Commit the transaction to the wallet
|
||||
bool Commit(bilingual_str& strResult);
|
||||
bool Commit(bilingual_str& strResult) LOCKS_EXCLUDED(cs_outputs);
|
||||
/// Convert to a string
|
||||
std::string ToString() const;
|
||||
|
||||
private:
|
||||
/// Clear the output vector and keep/return the included keys depending on the value of fKeepKeys
|
||||
void Clear();
|
||||
void Clear() LOCKS_EXCLUDED(cs_outputs);
|
||||
/// Get the total number of bytes used already by this transaction
|
||||
unsigned int GetBytesTotal() const;
|
||||
unsigned int GetBytesTotal() const LOCKS_EXCLUDED(cs_outputs);
|
||||
/// Helper to calculate static amount left by simply subtracting an used amount and a fee from a provided initial amount.
|
||||
static CAmount GetAmountLeft(CAmount nAmountInitial, CAmount nAmountUsed, CAmount nFee);
|
||||
/// Get the amount currently used by added outputs. Does not include fees.
|
||||
CAmount GetAmountUsed() const;
|
||||
CAmount GetAmountUsed() const LOCKS_EXCLUDED(cs_outputs);
|
||||
/// Get fees based on the number of bytes and the feerate set in CoinControl.
|
||||
/// NOTE: To get the total transaction fee this should only be called once with the total number of bytes for the transaction to avoid
|
||||
/// calling CFeeRate::GetFee multiple times with subtotals as this may add rounding errors with each further call.
|
||||
CAmount GetFee(unsigned int nBytes) const;
|
||||
/// Helper to get GetSizeOfCompactSizeDiff(vecOutputs.size(), vecOutputs.size() + nAdd)
|
||||
int GetSizeOfCompactSizeDiff(size_t nAdd) const;
|
||||
int GetSizeOfCompactSizeDiff(size_t nAdd) const LOCKS_EXCLUDED(cs_outputs);
|
||||
};
|
||||
|
||||
#endif // BITCOIN_COINJOIN_UTIL_H
|
||||
|
Loading…
Reference in New Issue
Block a user