Split PS into Manager and Session and allow running multiple mixing sessions in parallel (client side) (#2203)

* Split PS into Manager and Session

* Adjust log messages accordingly

* add -privatesendsessions cmd-line option

* address review comments

* bump MAX_OUTBOUND_MASTERNODE_CONNECTIONS to 30

+10 for parallel mixing

* protect vecSessions

* constructors

* Rewrite CMasternodeMan::ProcessMasternodeConnections() to use CPrivateSendClientManager::GetMixingMasternodesInfo().

This should solve potential deadlock cs_vecqueue vs cs_vNodes.

* Drop no longer used IsMixingMasternode()

* lock cs_wallet when mixing uses balance related functions
This commit is contained in:
UdjinM6 2018-09-04 13:54:59 +03:00 committed by GitHub
parent 794921b7b5
commit b164bcc7a5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 561 additions and 289 deletions

View File

@ -579,6 +579,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageGroup(_("PrivateSend options:")); strUsage += HelpMessageGroup(_("PrivateSend options:"));
strUsage += HelpMessageOpt("-enableprivatesend=<n>", strprintf(_("Enable use of automated PrivateSend for funds stored in this wallet (0-1, default: %u)"), 0)); strUsage += HelpMessageOpt("-enableprivatesend=<n>", strprintf(_("Enable use of automated PrivateSend for funds stored in this wallet (0-1, default: %u)"), 0));
strUsage += HelpMessageOpt("-privatesendmultisession=<n>", strprintf(_("Enable multiple PrivateSend mixing sessions per block, experimental (0-1, default: %u)"), DEFAULT_PRIVATESEND_MULTISESSION)); strUsage += HelpMessageOpt("-privatesendmultisession=<n>", strprintf(_("Enable multiple PrivateSend mixing sessions per block, experimental (0-1, default: %u)"), DEFAULT_PRIVATESEND_MULTISESSION));
strUsage += HelpMessageOpt("-privatesendsessions=<n>", strprintf(_("Use N separate masternodes in parallel to mix funds (%u-%u, default: %u)"), MIN_PRIVATESEND_SESSIONS, MAX_PRIVATESEND_SESSIONS, DEFAULT_PRIVATESEND_SESSIONS));
strUsage += HelpMessageOpt("-privatesendrounds=<n>", strprintf(_("Use N separate masternodes for each denominated input to mix funds (%u-%u, default: %u)"), MIN_PRIVATESEND_ROUNDS, MAX_PRIVATESEND_ROUNDS, DEFAULT_PRIVATESEND_ROUNDS)); strUsage += HelpMessageOpt("-privatesendrounds=<n>", strprintf(_("Use N separate masternodes for each denominated input to mix funds (%u-%u, default: %u)"), MIN_PRIVATESEND_ROUNDS, MAX_PRIVATESEND_ROUNDS, DEFAULT_PRIVATESEND_ROUNDS));
strUsage += HelpMessageOpt("-privatesendamount=<n>", strprintf(_("Keep N DASH anonymized (%u-%u, default: %u)"), MIN_PRIVATESEND_AMOUNT, MAX_PRIVATESEND_AMOUNT, DEFAULT_PRIVATESEND_AMOUNT)); strUsage += HelpMessageOpt("-privatesendamount=<n>", strprintf(_("Keep N DASH anonymized (%u-%u, default: %u)"), MIN_PRIVATESEND_AMOUNT, MAX_PRIVATESEND_AMOUNT, DEFAULT_PRIVATESEND_AMOUNT));
strUsage += HelpMessageOpt("-liquidityprovider=<n>", strprintf(_("Provide liquidity to PrivateSend by infrequently mixing coins on a continual basis (%u-%u, default: %u, 1=very frequent, high fees, %u=very infrequent, low fees)"), strUsage += HelpMessageOpt("-liquidityprovider=<n>", strprintf(_("Provide liquidity to PrivateSend by infrequently mixing coins on a continual basis (%u-%u, default: %u, 1=very frequent, high fees, %u=very infrequent, low fees)"),
@ -918,6 +919,8 @@ void InitParameterInteraction()
if (nLiqProvTmp > 0) { if (nLiqProvTmp > 0) {
ForceSetArg("-enableprivatesend", "1"); ForceSetArg("-enableprivatesend", "1");
LogPrintf("%s: parameter interaction: -liquidityprovider=%d -> setting -enableprivatesend=1\n", __func__, nLiqProvTmp); LogPrintf("%s: parameter interaction: -liquidityprovider=%d -> setting -enableprivatesend=1\n", __func__, nLiqProvTmp);
ForceSetArg("-privatesendsessions", itostr(MIN_PRIVATESEND_SESSIONS));
LogPrintf("%s: parameter interaction: -liquidityprovider=%d -> setting -privatesendsessions=%d\n", __func__, nLiqProvTmp, itostr(std::numeric_limits<int>::max()));
ForceSetArg("-privatesendrounds", itostr(std::numeric_limits<int>::max())); ForceSetArg("-privatesendrounds", itostr(std::numeric_limits<int>::max()));
LogPrintf("%s: parameter interaction: -liquidityprovider=%d -> setting -privatesendrounds=%d\n", __func__, nLiqProvTmp, itostr(std::numeric_limits<int>::max())); LogPrintf("%s: parameter interaction: -liquidityprovider=%d -> setting -privatesendrounds=%d\n", __func__, nLiqProvTmp, itostr(std::numeric_limits<int>::max()));
ForceSetArg("-privatesendamount", itostr(MAX_PRIVATESEND_AMOUNT)); ForceSetArg("-privatesendamount", itostr(MAX_PRIVATESEND_AMOUNT));
@ -1921,6 +1924,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
privateSendClient.fEnablePrivateSend = GetBoolArg("-enableprivatesend", false); privateSendClient.fEnablePrivateSend = GetBoolArg("-enableprivatesend", false);
privateSendClient.fPrivateSendMultiSession = GetBoolArg("-privatesendmultisession", DEFAULT_PRIVATESEND_MULTISESSION); privateSendClient.fPrivateSendMultiSession = GetBoolArg("-privatesendmultisession", DEFAULT_PRIVATESEND_MULTISESSION);
privateSendClient.nPrivateSendSessions = std::min(std::max((int)GetArg("-privatesendsessions", DEFAULT_PRIVATESEND_SESSIONS), MIN_PRIVATESEND_SESSIONS), MAX_PRIVATESEND_SESSIONS);
privateSendClient.nPrivateSendRounds = std::min(std::max((int)GetArg("-privatesendrounds", DEFAULT_PRIVATESEND_ROUNDS), MIN_PRIVATESEND_ROUNDS), nMaxRounds); privateSendClient.nPrivateSendRounds = std::min(std::max((int)GetArg("-privatesendrounds", DEFAULT_PRIVATESEND_ROUNDS), MIN_PRIVATESEND_ROUNDS), nMaxRounds);
privateSendClient.nPrivateSendAmount = std::min(std::max((int)GetArg("-privatesendamount", DEFAULT_PRIVATESEND_AMOUNT), MIN_PRIVATESEND_AMOUNT), MAX_PRIVATESEND_AMOUNT); privateSendClient.nPrivateSendAmount = std::min(std::max((int)GetArg("-privatesendamount", DEFAULT_PRIVATESEND_AMOUNT), MIN_PRIVATESEND_AMOUNT), MAX_PRIVATESEND_AMOUNT);
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
@ -2023,7 +2027,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler)
scheduler.scheduleEvery(boost::bind(&CPrivateSendServer::DoMaintenance, boost::ref(privateSendServer), boost::ref(*g_connman)), 1); scheduler.scheduleEvery(boost::bind(&CPrivateSendServer::DoMaintenance, boost::ref(privateSendServer), boost::ref(*g_connman)), 1);
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
else else
scheduler.scheduleEvery(boost::bind(&CPrivateSendClient::DoMaintenance, boost::ref(privateSendClient), boost::ref(*g_connman)), 1); scheduler.scheduleEvery(boost::bind(&CPrivateSendClientManager::DoMaintenance, boost::ref(privateSendClient), boost::ref(*g_connman)), 1);
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
} }

View File

@ -882,11 +882,22 @@ void CMasternodeMan::ProcessMasternodeConnections(CConnman& connman)
//we don't care about this for regtest //we don't care about this for regtest
if(Params().NetworkIDString() == CBaseChainParams::REGTEST) return; if(Params().NetworkIDString() == CBaseChainParams::REGTEST) return;
connman.ForEachNode(CConnman::AllNodes, [](CNode* pnode) { std::vector<masternode_info_t> vecMnInfo; // will be empty when no wallet
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
if(pnode->fMasternode && !privateSendClient.IsMixingMasternode(pnode)) { privateSendClient.GetMixingMasternodesInfo(vecMnInfo);
#else #endif // ENABLE_WALLET
if(pnode->fMasternode) {
connman.ForEachNode(CConnman::AllNodes, [&vecMnInfo](CNode* pnode) {
if (pnode->fMasternode) {
#ifdef ENABLE_WALLET
bool fFound = false;
for (const auto& mnInfo : vecMnInfo) {
if (pnode->addr == mnInfo.addr) {
fFound = true;
break;
}
}
if (fFound) return; // do NOT disconnect mixing masternodes
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
LogPrintf("Closing Masternode connection: peer=%d, addr=%s\n", pnode->id, pnode->addr.ToString()); LogPrintf("Closing Masternode connection: peer=%d, addr=%s\n", pnode->id, pnode->addr.ToString());
pnode->fDisconnect = true; pnode->fDisconnect = true;

View File

@ -65,7 +65,7 @@ static const int MAX_OUTBOUND_CONNECTIONS = 8;
/** Maximum number of addnode outgoing nodes */ /** Maximum number of addnode outgoing nodes */
static const int MAX_ADDNODE_CONNECTIONS = 8; static const int MAX_ADDNODE_CONNECTIONS = 8;
/** Maximum number if outgoing masternodes */ /** Maximum number if outgoing masternodes */
static const int MAX_OUTBOUND_MASTERNODE_CONNECTIONS = 20; static const int MAX_OUTBOUND_MASTERNODE_CONNECTIONS = 30;
/** -listen default */ /** -listen default */
static const bool DEFAULT_LISTEN = true; static const bool DEFAULT_LISTEN = true;
/** -upnp default */ /** -upnp default */

File diff suppressed because it is too large Load Diff

View File

@ -10,17 +10,20 @@
#include "wallet/wallet.h" #include "wallet/wallet.h"
#include "privatesend-util.h" #include "privatesend-util.h"
class CPrivateSendClient; class CPrivateSendClientManager;
class CConnman; class CConnman;
static const int DENOMS_COUNT_MAX = 100; static const int DENOMS_COUNT_MAX = 100;
static const int MIN_PRIVATESEND_SESSIONS = 1;
static const int MIN_PRIVATESEND_ROUNDS = 2; static const int MIN_PRIVATESEND_ROUNDS = 2;
static const int MIN_PRIVATESEND_AMOUNT = 2; static const int MIN_PRIVATESEND_AMOUNT = 2;
static const int MIN_PRIVATESEND_LIQUIDITY = 0; static const int MIN_PRIVATESEND_LIQUIDITY = 0;
static const int MAX_PRIVATESEND_SESSIONS = 10;
static const int MAX_PRIVATESEND_ROUNDS = 16; static const int MAX_PRIVATESEND_ROUNDS = 16;
static const int MAX_PRIVATESEND_AMOUNT = MAX_MONEY / COIN; static const int MAX_PRIVATESEND_AMOUNT = MAX_MONEY / COIN;
static const int MAX_PRIVATESEND_LIQUIDITY = 100; static const int MAX_PRIVATESEND_LIQUIDITY = 100;
static const int DEFAULT_PRIVATESEND_SESSIONS = 4;
static const int DEFAULT_PRIVATESEND_ROUNDS = 4; static const int DEFAULT_PRIVATESEND_ROUNDS = 4;
static const int DEFAULT_PRIVATESEND_AMOUNT = 1000; static const int DEFAULT_PRIVATESEND_AMOUNT = 1000;
static const int DEFAULT_PRIVATESEND_LIQUIDITY = 0; static const int DEFAULT_PRIVATESEND_LIQUIDITY = 0;
@ -34,7 +37,7 @@ static const int PRIVATESEND_KEYS_THRESHOLD_WARNING = 100;
static const int PRIVATESEND_KEYS_THRESHOLD_STOP = 50; static const int PRIVATESEND_KEYS_THRESHOLD_STOP = 50;
// The main object for accessing mixing // The main object for accessing mixing
extern CPrivateSendClient privateSendClient; extern CPrivateSendClientManager privateSendClient;
class CPendingDsaRequest class CPendingDsaRequest
{ {
@ -75,23 +78,11 @@ public:
} }
}; };
/** Used to keep track of current status of mixing pool class CPrivateSendClientSession : public CPrivateSendBaseSession
*/
class CPrivateSendClient : public CPrivateSendBase
{ {
private: private:
// Keep track of the used Masternodes
std::vector<COutPoint> vecMasternodesUsed;
std::vector<CAmount> vecDenominationsSkipped;
std::vector<COutPoint> vecOutPointLocked; std::vector<COutPoint> vecOutPointLocked;
int nCachedLastSuccessBlock;
int nMinBlocksToWait; // how many blocks to wait after one successful mixing tx in non-multisession mode
// Keep track of current block height
int nCachedBlockHeight;
int nEntriesCount; int nEntriesCount;
bool fLastEntryAccepted; bool fLastEntryAccepted;
@ -104,19 +95,6 @@ private:
CKeyHolderStorage keyHolderStorage; // storage for keys used in PrepareDenominate CKeyHolderStorage keyHolderStorage; // storage for keys used in PrepareDenominate
/// Check for process
void CheckPool();
void CompletedTransaction(PoolMessage nMessageID);
bool IsDenomSkipped(CAmount nDenomValue);
bool WaitForAnotherBlock();
// Make sure we have enough keys since last backup
bool CheckAutomaticBackup();
bool JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman);
bool StartNewQueue(CAmount nValueMin, CAmount nBalanceNeedsAnonymized, CConnman& connman);
/// Create denominations /// Create denominations
bool CreateDenominated(CConnman& connman); bool CreateDenominated(CConnman& connman);
bool CreateDenominated(const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals, CConnman& connman); bool CreateDenominated(const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals, CConnman& connman);
@ -125,8 +103,9 @@ private:
bool MakeCollateralAmounts(CConnman& connman); bool MakeCollateralAmounts(CConnman& connman);
bool MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated, CConnman& connman); bool MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated, CConnman& connman);
/// As a client, submit part of a future mixing transaction to a Masternode to start the process bool JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman);
bool SubmitDenominate(CConnman& connman); bool StartNewQueue(CAmount nValueMin, CAmount nBalanceNeedsAnonymized, CConnman& connman);
/// step 1: prepare denominated inputs and outputs /// step 1: prepare denominated inputs and outputs
bool PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, std::vector<CTxDSIn>& vecTxDSInRet, std::vector<CTxOut>& vecTxOutRet); bool PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, std::vector<CTxDSIn>& vecTxDSInRet, std::vector<CTxOut>& vecTxOutRet);
/// step 2: send denominated inputs and outputs prepared in step 1 /// step 2: send denominated inputs and outputs prepared in step 1
@ -137,6 +116,10 @@ private:
// Set the 'state' value, with some logging and capturing when the state changed // Set the 'state' value, with some logging and capturing when the state changed
void SetState(PoolState nStateNew); void SetState(PoolState nStateNew);
/// Check for process
void CheckPool();
void CompletedTransaction(PoolMessage nMessageID);
/// As a client, check and sign the final transaction /// 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);
@ -145,6 +128,68 @@ private:
void SetNull(); void SetNull();
public: public:
CPrivateSendClientSession() :
vecOutPointLocked(),
nEntriesCount(0),
fLastEntryAccepted(false),
strLastMessage(),
strAutoDenomResult(),
infoMixingMasternode(),
txMyCollateral(),
pendingDsaRequest(),
keyHolderStorage()
{}
CPrivateSendClientSession(const CPrivateSendClientSession& other) { /* dummy copy constructor*/ SetNull(); }
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman);
void UnlockCoins();
void ResetPool();
std::string GetStatus(bool fWaitForBlock);
bool GetMixingMasternodeInfo(masternode_info_t& mnInfoRet) const;
/// Passively run mixing in the background according to the configuration in settings
bool DoAutomaticDenominating(CConnman& connman, bool fDryRun=false);
/// As a client, submit part of a future mixing transaction to a Masternode to start the process
bool SubmitDenominate(CConnman& connman);
bool ProcessPendingDsaRequest(CConnman& connman);
bool CheckTimeout();
};
/** Used to keep track of current status of mixing pool
*/
class CPrivateSendClientManager : public CPrivateSendBaseManager
{
private:
// Keep track of the used Masternodes
std::vector<COutPoint> vecMasternodesUsed;
std::vector<CAmount> vecDenominationsSkipped;
// TODO: or map<denom, CPrivateSendClientSession> ??
std::vector<CPrivateSendClientSession> vecSessions;
mutable CCriticalSection cs_vecsessions;
int nCachedLastSuccessBlock;
int nMinBlocksToWait; // how many blocks to wait after one successful mixing tx in non-multisession mode
std::string strAutoDenomResult;
// Keep track of current block height
int nCachedBlockHeight;
bool WaitForAnotherBlock();
// Make sure we have enough keys since last backup
bool CheckAutomaticBackup();
public:
int nPrivateSendSessions;
int nPrivateSendRounds; int nPrivateSendRounds;
int nPrivateSendAmount; int nPrivateSendAmount;
int nLiquidityProvider; int nLiquidityProvider;
@ -154,40 +199,49 @@ public:
int nCachedNumBlocks; //used for the overview screen int nCachedNumBlocks; //used for the overview screen
bool fCreateAutoBackups; //builtin support for automatic backups bool fCreateAutoBackups; //builtin support for automatic backups
CPrivateSendClient() : CPrivateSendClientManager() :
vecMasternodesUsed(),
vecDenominationsSkipped(),
vecSessions(),
nCachedLastSuccessBlock(0), nCachedLastSuccessBlock(0),
nMinBlocksToWait(1), nMinBlocksToWait(1),
txMyCollateral(CMutableTransaction()), strAutoDenomResult(),
nCachedBlockHeight(0),
nPrivateSendRounds(DEFAULT_PRIVATESEND_ROUNDS), nPrivateSendRounds(DEFAULT_PRIVATESEND_ROUNDS),
nPrivateSendAmount(DEFAULT_PRIVATESEND_AMOUNT), nPrivateSendAmount(DEFAULT_PRIVATESEND_AMOUNT),
nLiquidityProvider(DEFAULT_PRIVATESEND_LIQUIDITY), nLiquidityProvider(DEFAULT_PRIVATESEND_LIQUIDITY),
fEnablePrivateSend(false), fEnablePrivateSend(false),
fPrivateSendMultiSession(DEFAULT_PRIVATESEND_MULTISESSION), fPrivateSendMultiSession(DEFAULT_PRIVATESEND_MULTISESSION),
nCachedNumBlocks(std::numeric_limits<int>::max()), nCachedNumBlocks(std::numeric_limits<int>::max()),
fCreateAutoBackups(true) { SetNull(); } fCreateAutoBackups(true)
{}
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman);
bool IsDenomSkipped(const CAmount& nDenomValue);
void AddSkippedDenom(const CAmount& nDenomValue);
void ClearSkippedDenominations() { vecDenominationsSkipped.clear(); } void ClearSkippedDenominations() { vecDenominationsSkipped.clear(); }
void SetMinBlocksToWait(int nMinBlocksToWaitIn) { nMinBlocksToWait = nMinBlocksToWaitIn; } void SetMinBlocksToWait(int nMinBlocksToWaitIn) { nMinBlocksToWait = nMinBlocksToWaitIn; }
void ResetPool(); void ResetPool();
void UnlockCoins(); std::string GetStatuses();
std::string GetSessionDenoms();
std::string GetStatus(); bool GetMixingMasternodesInfo(std::vector<masternode_info_t>& vecMnInfoRet) const;
bool GetMixingMasternodeInfo(masternode_info_t& mnInfoRet);
bool IsMixingMasternode(const CNode* pnode);
/// Passively run mixing in the background according to the configuration in settings /// 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);
void CheckTimeout();
void ProcessPendingDsaRequest(CConnman& connman); void ProcessPendingDsaRequest(CConnman& connman);
void CheckTimeout(); void AddUsedMasternode(const COutPoint& outpointMn);
masternode_info_t GetNotUsedMasternode();
void UpdatedSuccessBlock();
void UpdatedBlockTip(const CBlockIndex *pindex); void UpdatedBlockTip(const CBlockIndex *pindex);

View File

@ -76,7 +76,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strComm
} }
} else if(strCommand == NetMsgType::DSQUEUE) { } else if(strCommand == NetMsgType::DSQUEUE) {
TRY_LOCK(cs_darksend, lockRecv); TRY_LOCK(cs_vecqueue, lockRecv);
if(!lockRecv) return; if(!lockRecv) return;
if(pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) { if(pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) {
@ -282,7 +282,8 @@ void CPrivateSendServer::SetNull()
// MN side // MN side
vecSessionCollaterals.clear(); vecSessionCollaterals.clear();
CPrivateSendBase::SetNull(); CPrivateSendBaseSession::SetNull();
CPrivateSendBaseManager::SetNull();
} }
// //

View File

@ -15,7 +15,7 @@ extern CPrivateSendServer privateSendServer;
/** Used to keep track of current status of mixing pool /** Used to keep track of current status of mixing pool
*/ */
class CPrivateSendServer : public CPrivateSendBase class CPrivateSendServer : public CPrivateSendBaseSession, public CPrivateSendBaseManager
{ {
private: private:
// Mixing uses collateral transactions to trust parties entering the pool // Mixing uses collateral transactions to trust parties entering the pool
@ -66,8 +66,7 @@ private:
void SetNull(); void SetNull();
public: public:
CPrivateSendServer() : CPrivateSendServer() : vecSessionCollaterals(), fUnitTest(false) {}
fUnitTest(false) { SetNull(); }
void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman); void ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman);

View File

@ -183,9 +183,10 @@ bool CDarksendBroadcastTx::IsExpired(int nHeight)
return (nConfirmedHeight != -1) && (nHeight - nConfirmedHeight > 24); return (nConfirmedHeight != -1) && (nHeight - nConfirmedHeight > 24);
} }
void CPrivateSendBase::SetNull() void CPrivateSendBaseSession::SetNull()
{ {
// Both sides // Both sides
LOCK(cs_darksend);
nState = POOL_STATE_IDLE; nState = POOL_STATE_IDLE;
nSessionID = 0; nSessionID = 0;
nSessionDenom = 0; nSessionDenom = 0;
@ -196,22 +197,44 @@ void CPrivateSendBase::SetNull()
nTimeLastSuccessfulStep = GetTime(); nTimeLastSuccessfulStep = GetTime();
} }
void CPrivateSendBase::CheckQueue() void CPrivateSendBaseManager::SetNull()
{ {
TRY_LOCK(cs_darksend, lockDS); LOCK(cs_vecqueue);
vecDarksendQueue.clear();
}
void CPrivateSendBaseManager::CheckQueue()
{
TRY_LOCK(cs_vecqueue, lockDS);
if(!lockDS) return; // it's ok to fail here, we run this quite frequently if(!lockDS) return; // it's ok to fail here, we run this quite frequently
// check mixing queue objects for timeouts // check mixing queue objects for timeouts
std::vector<CDarksendQueue>::iterator it = vecDarksendQueue.begin(); std::vector<CDarksendQueue>::iterator it = vecDarksendQueue.begin();
while(it != vecDarksendQueue.end()) { while(it != vecDarksendQueue.end()) {
if((*it).IsExpired()) { if((*it).IsExpired()) {
LogPrint("privatesend", "CPrivateSendBase::%s -- Removing expired queue (%s)\n", __func__, (*it).ToString()); LogPrint("privatesend", "CPrivateSendBaseManager::%s -- Removing expired queue (%s)\n", __func__, (*it).ToString());
it = vecDarksendQueue.erase(it); it = vecDarksendQueue.erase(it);
} else ++it; } else ++it;
} }
} }
std::string CPrivateSendBase::GetStateString() const bool CPrivateSendBaseManager::GetQueueItemAndTry(CDarksendQueue& dsqRet)
{
TRY_LOCK(cs_vecqueue, lockDS);
if(!lockDS) return false; // it's ok to fail here, we run this quite frequently
for (auto& dsq : vecDarksendQueue) {
// only try each queue once
if(dsq.fTried || dsq.IsExpired()) continue;
dsq.fTried = true;
dsqRet = dsq;
return true;
}
return false;
}
std::string CPrivateSendBaseSession::GetStateString() const
{ {
switch(nState) { switch(nState) {
case POOL_STATE_IDLE: return "IDLE"; case POOL_STATE_IDLE: return "IDLE";
@ -504,5 +527,5 @@ void CPrivateSend::SyncTransaction(const CTransaction& tx, const CBlockIndex *pi
// When tx is 0-confirmed or conflicted, posInBlock is SYNC_TRANSACTION_NOT_IN_BLOCK and nConfirmedHeight should be set to -1 // When tx is 0-confirmed or conflicted, posInBlock is SYNC_TRANSACTION_NOT_IN_BLOCK and nConfirmedHeight should be set to -1
mapDSTX[txHash].SetConfirmedHeight(posInBlock == CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK ? -1 : pindex->nHeight); mapDSTX[txHash].SetConfirmedHeight(posInBlock == CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK ? -1 : pindex->nHeight);
LogPrint("privatesend", "CPrivateSendClient::SyncTransaction -- txid=%s\n", txHash.ToString()); LogPrint("privatesend", "CPrivateSend::SyncTransaction -- txid=%s\n", txHash.ToString());
} }

View File

@ -348,14 +348,11 @@ public:
}; };
// base class // base class
class CPrivateSendBase class CPrivateSendBaseSession
{ {
protected: protected:
mutable CCriticalSection cs_darksend; mutable CCriticalSection cs_darksend;
// The current mixing sessions in progress on the network
std::vector<CDarksendQueue> vecDarksendQueue;
std::vector<CDarkSendEntry> vecEntries; // Masternode/clients entries std::vector<CDarkSendEntry> vecEntries; // Masternode/clients entries
PoolState nState; // should be one of the POOL_STATE_XXX values PoolState nState; // should be one of the POOL_STATE_XXX values
@ -366,21 +363,47 @@ protected:
CMutableTransaction finalMutableTransaction; // the finalized transaction ready for signing CMutableTransaction finalMutableTransaction; // the finalized transaction ready for signing
void SetNull(); void SetNull();
void CheckQueue();
public: public:
int nSessionDenom; //Users must submit an denom matching this int nSessionDenom; //Users must submit a denom matching this
int nSessionInputCount; //Users must submit a count matching this int nSessionInputCount; //Users must submit a count matching this
CPrivateSendBase() { SetNull(); } CPrivateSendBaseSession() :
vecEntries(),
nState(POOL_STATE_IDLE),
nTimeLastSuccessfulStep(0),
nSessionID(0),
finalMutableTransaction(),
nSessionDenom(0),
nSessionInputCount(0)
{}
CPrivateSendBaseSession(const CPrivateSendBaseSession& other) { /* dummy copy constructor*/ SetNull(); }
int GetQueueSize() const { return vecDarksendQueue.size(); }
int GetState() const { return nState; } int GetState() const { return nState; }
std::string GetStateString() const; std::string GetStateString() const;
int GetEntriesCount() const { return vecEntries.size(); } int GetEntriesCount() const { return vecEntries.size(); }
}; };
// base class
class CPrivateSendBaseManager
{
protected:
mutable CCriticalSection cs_vecqueue;
// The current mixing sessions in progress on the network
std::vector<CDarksendQueue> vecDarksendQueue;
void SetNull();
void CheckQueue();
public:
CPrivateSendBaseManager() : vecDarksendQueue() {}
int GetQueueSize() const { return vecDarksendQueue.size(); }
bool GetQueueItemAndTry(CDarksendQueue& dsqRet);
};
// helper class // helper class
class CPrivateSend class CPrivateSend
{ {

View File

@ -564,7 +564,7 @@ void OverviewPage::privateSendStatus()
updatePrivateSendProgress(); updatePrivateSendProgress();
} }
QString strStatus = QString(privateSendClient.GetStatus().c_str()); QString strStatus = QString(privateSendClient.GetStatuses().c_str());
QString s = tr("Last PrivateSend message:\n") + strStatus; QString s = tr("Last PrivateSend message:\n") + strStatus;
@ -573,13 +573,7 @@ void OverviewPage::privateSendStatus()
ui->labelPrivateSendLastMessage->setText(s); ui->labelPrivateSendLastMessage->setText(s);
if(privateSendClient.nSessionDenom == 0){ ui->labelSubmittedDenom->setText(QString(privateSendClient.GetSessionDenoms().c_str()));
ui->labelSubmittedDenom->setText(tr("N/A"));
} else {
QString strDenom(CPrivateSend::GetDenominationsToString(privateSendClient.nSessionDenom).c_str());
ui->labelSubmittedDenom->setText(strDenom);
}
} }
void OverviewPage::privateSendAuto(){ void OverviewPage::privateSendAuto(){
@ -642,7 +636,7 @@ void OverviewPage::togglePrivateSend(){
if(!privateSendClient.fEnablePrivateSend){ if(!privateSendClient.fEnablePrivateSend){
ui->togglePrivateSend->setText(tr("Start Mixing")); ui->togglePrivateSend->setText(tr("Start Mixing"));
privateSendClient.UnlockCoins(); privateSendClient.ResetPool();
} else { } else {
ui->togglePrivateSend->setText(tr("Stop Mixing")); ui->togglePrivateSend->setText(tr("Stop Mixing"));
} }

View File

@ -63,7 +63,7 @@ UniValue privatesend(const JSONRPCRequest& request)
privateSendClient.fEnablePrivateSend = true; privateSendClient.fEnablePrivateSend = true;
bool result = privateSendClient.DoAutomaticDenominating(*g_connman); bool result = privateSendClient.DoAutomaticDenominating(*g_connman);
return "Mixing " + (result ? "started successfully" : ("start failed: " + privateSendClient.GetStatus() + ", will retry")); return "Mixing " + (result ? "started successfully" : ("start failed: " + privateSendClient.GetStatuses() + ", will retry"));
} }
if(request.params[0].get_str() == "stop") { if(request.params[0].get_str() == "stop") {
@ -88,19 +88,25 @@ UniValue getpoolinfo(const JSONRPCRequest& request)
"Returns an object containing mixing pool related information.\n"); "Returns an object containing mixing pool related information.\n");
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
CPrivateSendBase* pprivateSendBase = fMasternodeMode ? (CPrivateSendBase*)&privateSendServer : (CPrivateSendBase*)&privateSendClient; CPrivateSendBaseManager* pprivateSendBaseManager = fMasternodeMode ? (CPrivateSendBaseManager*)&privateSendServer : (CPrivateSendBaseManager*)&privateSendClient;
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("state", pprivateSendBase->GetStateString())); // TODO:
obj.push_back(Pair("mixing_mode", (!fMasternodeMode && privateSendClient.fPrivateSendMultiSession) ? "multi-session" : "normal")); // obj.push_back(Pair("state", pprivateSendBase->GetStateString()));
obj.push_back(Pair("queue", pprivateSendBase->GetQueueSize())); obj.push_back(Pair("queue", pprivateSendBaseManager->GetQueueSize()));
obj.push_back(Pair("entries", pprivateSendBase->GetEntriesCount())); // obj.push_back(Pair("entries", pprivateSendBase->GetEntriesCount()));
obj.push_back(Pair("status", privateSendClient.GetStatus())); obj.push_back(Pair("status", privateSendClient.GetStatuses()));
masternode_info_t mnInfo; std::vector<masternode_info_t> vecMnInfo;
if (privateSendClient.GetMixingMasternodeInfo(mnInfo)) { if (privateSendClient.GetMixingMasternodesInfo(vecMnInfo)) {
obj.push_back(Pair("outpoint", mnInfo.outpoint.ToStringShort())); UniValue pools(UniValue::VARR);
obj.push_back(Pair("addr", mnInfo.addr.ToString())); for (const auto& mnInfo : vecMnInfo) {
UniValue pool(UniValue::VOBJ);
pool.push_back(Pair("outpoint", mnInfo.outpoint.ToStringShort()));
pool.push_back(Pair("addr", mnInfo.addr.ToString()));
pools.push_back(pool);
}
obj.push_back(Pair("pools", pools));
} }
if (pwalletMain) { if (pwalletMain) {