From 9908ca7c050ce170fea81f53b30265bb1608cd96 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Fri, 28 Oct 2016 00:06:33 +0300 Subject: [PATCH 1/4] PS changes: Refactoring: - IsDenomCompatibleWithSession, split in 3 - CreateNewSession, AddUserToExistingSession and IsAcceptableDenomAndCollateral - CheckTimeout: - should not rely on CDarkSendEntry nTimeAdded to clear entries, instead should rely on time of the last successful step i.e. nLastTimeChanged - nLastTimeChanged should only be set when mixing moved forward in some way State related: - local pool should be in POOL_STATE_IDLE initially - local pool should switch to POOL_STATE_QUEUE when connected to mn - local pool should set session id only when in POOL_STATE_QUEUE - SetState should set state local only, no relaying - mixing wallets should rely on local logic and expected set of state switches rather then updates from masternodes - deprecate STATUS_SET_STATE, POOL_STATE_UNKNOWN, POOL_STATE_TRANSMISSION, POOL_STATE_FINALIZE_TRANSACTION Session related: - deprecate fSessionFoundMasternode, use nSessionID instead - deprecate nSessionUsers, use vecSessionCollaterals.size() instead Other: - deprecate IsNull() - move few things to private - remove deprecated - bump min ps peer proto --- src/darksend.cpp | 286 +++++++++++++++++++++-------------------------- src/darksend.h | 50 +++------ 2 files changed, 148 insertions(+), 188 deletions(-) diff --git a/src/darksend.cpp b/src/darksend.cpp index 6820aed5b..c8fbd341a 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -76,7 +76,10 @@ void CDarksendPool::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataS } PoolMessage nMessageID = MSG_NOERR; - if(IsDenomCompatibleWithSession(nDenom, txCollateral, nMessageID)) { + + bool fResult = nSessionID == 0 ? CreateNewSession(nDenom, txCollateral, nMessageID) + : AddUserToExistingSession(nDenom, txCollateral, nMessageID); + if(fResult) { LogPrintf("DSACCEPT -- is compatible, please submit!\n"); PushStatus(pfrom, STATUS_ACCEPTED, nMessageID); return; @@ -263,9 +266,10 @@ void CDarksendPool::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataS if(AddEntry(entry, nMessageID)) { PushStatus(pfrom, STATUS_ACCEPTED, nMessageID); CheckPool(); - RelayStatus(STATUS_SET_STATE); + RelayStatus(STATUS_ACCEPTED); } else { PushStatus(pfrom, STATUS_REJECTED, nMessageID); + SetNull(); } } else if(strCommand == NetMsgType::DSSTATUSUPDATE) { @@ -301,7 +305,7 @@ void CDarksendPool::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataS return; } - if(nMsgStatusUpdate < STATUS_SET_STATE || nMsgStatusUpdate > STATUS_ACCEPTED) { + if(nMsgStatusUpdate < STATUS_REJECTED || nMsgStatusUpdate > STATUS_ACCEPTED) { LogPrint("privatesend", "DSSTATUSUPDATE -- nMsgStatusUpdate is out of bounds: %d\n", nMsgStatusUpdate); return; } @@ -313,13 +317,10 @@ void CDarksendPool::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataS LogPrint("privatesend", "DSSTATUSUPDATE -- GetMessageByID: %s\n", GetMessageByID(PoolMessage(nMsgMessageID))); - if(nMsgStatusUpdate == STATUS_SET_STATE && nSessionID != nMsgSessionID) { - LogPrint("privatesend", "DSSTATUSUPDATE -- message doesn't match current PrivateSend session: nSessionID: %d nMsgSessionID: %d\n", nSessionID, nMsgSessionID); - return; + if(!UpdatePoolStateOnClient(PoolState(nMsgState), nMsgEntriesCount, PoolStatusUpdate(nMsgStatusUpdate), PoolMessage(nMsgMessageID), nMsgSessionID)) { + LogPrint("privatesend", "DSSTATUSUPDATE -- can't update local state\n"); } - UpdatePoolStateOnClient(PoolState(nMsgState), nMsgEntriesCount, PoolStatusUpdate(nMsgStatusUpdate), PoolMessage(nMsgMessageID), nMsgSessionID); - } else if(strCommand == NetMsgType::DSSIGNFINALTX) { if(pfrom->nVersion < MIN_PRIVATESEND_PEER_PROTO_VERSION) { @@ -344,13 +345,13 @@ void CDarksendPool::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataS nTxInIndex++; if(!AddScriptSig(txin)) { LogPrint("privatesend", "DSSIGNFINALTX -- AddScriptSig() failed at %d/%d, session: %d\n", nTxInIndex, nTxInsCount, nSessionID); + RelayStatus(STATUS_REJECTED); return; } LogPrint("privatesend", "DSSIGNFINALTX -- AddScriptSig() %d/%d success\n", nTxInIndex, nTxInsCount); } // all is good CheckPool(); - RelayStatus(STATUS_SET_STATE); } else if(strCommand == NetMsgType::DSFINALTX) { @@ -456,13 +457,11 @@ void CDarksendPool::ResetPool() void CDarksendPool::SetNull() { // MN side - nSessionUsers = 0; vecSessionCollaterals.clear(); // Client side nEntriesCount = 0; fLastEntryAccepted = false; - fSessionFoundMasternode = false; // Both sides nState = POOL_STATE_IDLE; @@ -530,10 +529,6 @@ std::string CDarksendPool::GetStatus() else if(nStatusMessageProgress % 70 <= 60) strSuffix = ".."; else if(nStatusMessageProgress % 70 <= 70) strSuffix = "..."; return strprintf(_("Found enough users, signing ( waiting %s )"), strSuffix); - case POOL_STATE_TRANSMISSION: - return _("Transmitting final transaction."); - case POOL_STATE_FINALIZE_TRANSACTION: - return _("Finalizing transaction."); case POOL_STATE_ERROR: return _("PrivateSend request incomplete:") + " " + strLastMessage + " " + _("Will retry..."); case POOL_STATE_SUCCESS: @@ -551,23 +546,19 @@ void CDarksendPool::CheckPool() if(fMasterNode) { LogPrint("privatesend", "CDarksendPool::CheckPool -- entries count %lu\n", GetEntriesCount()); - // If entries are full, then move on to the next phase + // If entries are full, create finalized transaction if(nState == POOL_STATE_ACCEPTING_ENTRIES && GetEntriesCount() >= GetMaxPoolTransactions()) { - LogPrint("privatesend", "CDarksendPool::CheckPool -- TRYING TRANSACTION\n"); - SetState(POOL_STATE_FINALIZE_TRANSACTION); + LogPrint("privatesend", "CDarksendPool::CheckPool -- FINALIZE TRANSACTIONS\n"); + CreateFinalTransaction(); + return; } - } - // create the finalized transaction for distribution to the clients - if(nState == POOL_STATE_FINALIZE_TRANSACTION) { - CreateFinalTransaction(); - } - - // If we have all of the signatures, try to compile the transaction - if(fMasterNode && nState == POOL_STATE_SIGNING && IsSignaturesComplete()) { - LogPrint("privatesend", "CDarksendPool::CheckPool -- SIGNING\n"); - SetState(POOL_STATE_TRANSMISSION); - CommitFinalTransaction(); + // If we have all of the signatures, try to compile the transaction + if(nState == POOL_STATE_SIGNING && IsSignaturesComplete()) { + LogPrint("privatesend", "CDarksendPool::CheckPool -- SIGNING\n"); + CommitFinalTransaction(); + return; + } } // reset if we're here for 10 seconds @@ -575,9 +566,6 @@ void CDarksendPool::CheckPool() LogPrint("privatesend", "CDarksendPool::CheckPool -- timeout, RESETTING\n"); UnlockCoins(); SetNull(); - if(fMasterNode) { - RelayStatus(STATUS_SET_STATE); - } } } @@ -626,9 +614,7 @@ void CDarksendPool::CommitFinalTransaction() { LogPrintf("CDarksendPool::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n"); SetNull(); - - // not much we can do in this case - SetState(POOL_STATE_ACCEPTING_ENTRIES); + // not much we can do in this case, just notify clients RelayCompletedTransaction(ERR_INVALID_TX); return; } @@ -657,7 +643,6 @@ void CDarksendPool::CommitFinalTransaction() // Reset LogPrint("privatesend", "CDarksendPool::CommitFinalTransaction -- COMPLETED -- RESETTING\n"); SetNull(); - RelayStatus(STATUS_SET_STATE); } // @@ -787,10 +772,6 @@ void CDarksendPool::CheckTimeout() // catching hanging sessions if(!fMasterNode) { switch(nState) { - case POOL_STATE_TRANSMISSION: - LogPrint("privatesend", "CDarksendPool::CheckTimeout -- Session complete -- Running CheckPool\n"); - CheckPool(); - break; case POOL_STATE_ERROR: LogPrint("privatesend", "CDarksendPool::CheckTimeout -- Pool error -- Running CheckPool\n"); CheckPool(); @@ -804,50 +785,18 @@ void CDarksendPool::CheckTimeout() } } - int nLagTime = 0; - if(!fMasterNode) nLagTime = 10000; //if we're the client, give the server a few extra seconds before resetting. + int nLagTime = fMasterNode ? 0 : 10000; // if we're the client, give the server a few extra seconds before resetting. + int nTimeout = (nState == POOL_STATE_SIGNING) ? PRIVATESEND_SIGNING_TIMEOUT : PRIVATESEND_QUEUE_TIMEOUT; + bool fTimeout = GetTimeMillis() - nLastTimeChanged >= nTimeout*1000 + nLagTime; - if(nState == POOL_STATE_ACCEPTING_ENTRIES || nState == POOL_STATE_QUEUE) { - int c = 0; - - // check for a timeout and reset if needed - std::vector::iterator it2 = vecEntries.begin(); - while(it2 != vecEntries.end()) { - if((*it2).IsExpired()) { - LogPrint("privatesend", "CDarksendPool::CheckTimeout -- Removing expired entry: %d\n", c); - it2 = vecEntries.erase(it2); - if(GetEntriesCount() == 0) { - UnlockCoins(); - SetNull(); - } - if(fMasterNode) { - RelayStatus(STATUS_SET_STATE); - } - } else ++it2; - c++; - } - - if(GetTimeMillis() - nLastTimeChanged >= PRIVATESEND_QUEUE_TIMEOUT*1000 + nLagTime) { - UnlockCoins(); - SetNull(); - } - } else if (GetTimeMillis() - nLastTimeChanged >= PRIVATESEND_QUEUE_TIMEOUT*1000 + nLagTime) { - LogPrint("privatesend", "CDarksendPool::CheckTimeout -- Session timed out (%ds) -- resetting\n", PRIVATESEND_QUEUE_TIMEOUT); - UnlockCoins(); - SetNull(); - - SetState(POOL_STATE_ERROR); - strLastMessage = _("Session timed out."); - } - - if(nState == POOL_STATE_SIGNING && GetTimeMillis() - nLastTimeChanged >= PRIVATESEND_SIGNING_TIMEOUT*1000 + nLagTime) { - LogPrint("privatesend", "CDarksendPool::CheckTimeout -- Session timed out (%ds) -- restting\n", PRIVATESEND_SIGNING_TIMEOUT); + if(nState != POOL_STATE_IDLE && fTimeout) { + LogPrint("privatesend", "CDarksendPool::CheckTimeout -- %s timed out (%ds) -- restting\n", + (nState == POOL_STATE_SIGNING) ? "Signing" : "Session", nTimeout); ChargeFees(); UnlockCoins(); SetNull(); - SetState(POOL_STATE_ERROR); - strLastMessage = _("Signing timed out."); + strLastMessage = _("Session timed out."); } } @@ -980,7 +929,6 @@ bool CDarksendPool::AddEntry(const CDarkSendEntry& entryNew, PoolMessage& nMessa if(txin.prevout.IsNull()) { LogPrint("privatesend", "CDarksendPool::AddEntry -- input not valid!\n"); nMessageIDRet = ERR_INVALID_INPUT; - nSessionUsers--; return false; } } @@ -988,14 +936,12 @@ bool CDarksendPool::AddEntry(const CDarkSendEntry& entryNew, PoolMessage& nMessa if(!IsCollateralValid(entryNew.txCollateral)) { LogPrint("privatesend", "CDarksendPool::AddEntry -- collateral not valid!\n"); nMessageIDRet = ERR_INVALID_COLLATERAL; - nSessionUsers--; return false; } if(GetEntriesCount() >= GetMaxPoolTransactions()) { LogPrint("privatesend", "CDarksendPool::AddEntry -- entries is full!\n"); nMessageIDRet = ERR_ENTRIES_FULL; - nSessionUsers--; return false; } @@ -1006,7 +952,6 @@ bool CDarksendPool::AddEntry(const CDarkSendEntry& entryNew, PoolMessage& nMessa if(txdsin.prevout == txin.prevout) { LogPrint("privatesend", "CDarksendPool::AddEntry -- found in txin\n"); nMessageIDRet = ERR_ALREADY_HAVE; - nSessionUsers--; return false; } } @@ -1017,6 +962,7 @@ bool CDarksendPool::AddEntry(const CDarkSendEntry& entryNew, PoolMessage& nMessa LogPrint("privatesend", "CDarksendPool::AddEntry -- adding entry\n"); nMessageIDRet = MSG_ENTRIES_ADDED; + nLastTimeChanged = GetTimeMillis(); return true; } @@ -1093,7 +1039,7 @@ bool CDarksendPool::SendDenominate(const std::vector& vecTxIn, const std: vecOutPointLocked.push_back(txin.prevout); // we should already be connected to a Masternode - if(!fSessionFoundMasternode) { + if(!nSessionID) { LogPrintf("CDarksendPool::SendDenominate -- No Masternode has been selected yet.\n"); UnlockCoins(); SetNull(); @@ -1143,9 +1089,8 @@ bool CDarksendPool::SendDenominate(const std::vector& vecTxIn, const std: // store our entry for later use CDarkSendEntry entry(vecTxIn, vecTxOut, txMyCollateral); vecEntries.push_back(entry); - RelayIn(entry); - CheckPool(); + nLastTimeChanged = GetTimeMillis(); return true; } @@ -1154,43 +1099,41 @@ bool CDarksendPool::SendDenominate(const std::vector& vecTxIn, const std: bool CDarksendPool::UpdatePoolStateOnClient(PoolState nStateNew, int nEntriesCountNew, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, int nSessionIDNew) { if(fMasterNode) return false; - if(nState == POOL_STATE_ERROR || nState == POOL_STATE_SUCCESS) return false; - SetState(nStateNew); - nEntriesCount = nEntriesCountNew; + // do not update state when mixing client state is one of these + if(nState == POOL_STATE_IDLE || nState == POOL_STATE_ERROR || nState == POOL_STATE_SUCCESS) return false; strAutoDenomResult = _("Masternode:") + " " + GetMessageByID(nMessageID); - if(nStatusUpdate != STATUS_SET_STATE) { - fLastEntryAccepted = nStatusUpdate; - if(nStatusUpdate == STATUS_REJECTED) { - SetState(POOL_STATE_ERROR); - strLastMessage = GetMessageByID(nMessageID); - } + // if rejected at any state + if(nStatusUpdate == STATUS_REJECTED) { + LogPrintf("CDarksendPool::UpdatePoolStateOnClient -- entry is rejected by Masternode\n"); + UnlockCoins(); + SetNull(); + SetState(POOL_STATE_ERROR); + strLastMessage = GetMessageByID(nMessageID); + return true; + } - if(nStatusUpdate == STATUS_ACCEPTED && nSessionIDNew != 0) { + if(nStatusUpdate == STATUS_ACCEPTED && nState == nStateNew) { + if(nStateNew == POOL_STATE_QUEUE && nSessionID == 0 && nSessionIDNew != 0) { + // new session id should be set only in POOL_STATE_QUEUE state nSessionID = nSessionIDNew; + nLastTimeChanged = GetTimeMillis(); LogPrintf("CDarksendPool::UpdatePoolStateOnClient -- set nSessionID to %d\n", nSessionID); - fSessionFoundMasternode = true; + return true; + } + else if(nStateNew == POOL_STATE_ACCEPTING_ENTRIES && nEntriesCount != nEntriesCountNew) { + nEntriesCount = nEntriesCountNew; + nLastTimeChanged = GetTimeMillis(); + fLastEntryAccepted = true; + LogPrintf("CDarksendPool::UpdatePoolStateOnClient -- new entry accepted!\n"); + return true; } } - if(nStateNew == POOL_STATE_ACCEPTING_ENTRIES) { - if(nStatusUpdate == STATUS_ACCEPTED) { - LogPrintf("CDarksendPool::UpdatePoolStateOnClient -- entry accepted!\n"); - fSessionFoundMasternode = true; - //wait for other users. Masternode will report when ready - SetState(POOL_STATE_QUEUE); - } else if(nStatusUpdate == STATUS_REJECTED && nSessionID == 0 && !fSessionFoundMasternode) { - LogPrintf("CDarksendPool::UpdatePoolStateOnClient -- entry not accepted by Masternode\n"); - UnlockCoins(); - SetState(POOL_STATE_ACCEPTING_ENTRIES); - DoAutomaticDenominating(); //try another Masternode - } - if(fSessionFoundMasternode) return true; - } - - return true; + // only situations above are allowed, fail in any other case + return false; } // @@ -1274,8 +1217,10 @@ bool CDarksendPool::SignFinalTransaction(const CTransaction& finalTransactionNew } // push all of our signatures to the Masternode - if(!sigs.empty() && pnode != NULL) - pnode->PushMessage(NetMsgType::DSSIGNFINALTX, sigs); + LogPrintf("CDarksendPool::SignFinalTransaction -- pushing sigs to the masternode, finalMutableTransaction=%s", finalMutableTransaction.ToString()); + pnode->PushMessage(NetMsgType::DSSIGNFINALTX, sigs); + nLastTimeChanged = GetTimeMillis(); + SetState(POOL_STATE_SIGNING); return true; } @@ -1488,7 +1433,7 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun) if(!pwalletMain->HasCollateralInputs()) return !pwalletMain->HasCollateralInputs(false) && MakeCollateralAmounts(); - if(fSessionFoundMasternode) { + if(nSessionID) { strAutoDenomResult = _("Mixing in progress..."); return false; } @@ -1498,8 +1443,6 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun) UnlockCoins(); SetNull(); - SetState(POOL_STATE_ACCEPTING_ENTRIES); - if(!fPrivateSendMultiSession && pwalletMain->GetDenominatedBalance(true) > 0) { //get denominated unconfirmed inputs LogPrintf("CDarksendPool::DoAutomaticDenominating -- Found unconfirmed denominated outputs, will wait till they confirm to continue.\n"); strAutoDenomResult = _("Found unconfirmed denominated outputs, will wait till they confirm to continue."); @@ -1544,6 +1487,7 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun) // only try each queue once if(dsq.fTried) continue; dsq.fTried = true; + if(dsq.IsExpired()) continue; CMasternode* pmn = mnodeman.Find(dsq.vin); @@ -1574,7 +1518,6 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun) vecMasternodesUsed.push_back(dsq.vin); LogPrintf("CDarksendPool::DoAutomaticDenominating -- attempt to connect to masternode from queue, addr=%s\n", pmn->addr.ToString()); - nLastTimeChanged = GetTimeMillis(); // connect to Masternode and submit the queue request CNode* pnode = ConnectNode((CAddress)pmn->addr, NULL, true); if(pnode) { @@ -1585,6 +1528,8 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun) LogPrintf("CDarksendPool::DoAutomaticDenominating -- connected (from queue), sending DSACCEPT: nSessionDenom: %d (%s), addr=%s\n", nSessionDenom, GetDenominationsToString(nSessionDenom), pnode->addr.ToString()); strAutoDenomResult = _("Mixing in progress..."); + nLastTimeChanged = GetTimeMillis(); + SetState(POOL_STATE_QUEUE); return true; } else { LogPrintf("CDarksendPool::DoAutomaticDenominating -- can't connect, addr=%s\n", pmn->addr.ToString()); @@ -1619,7 +1564,6 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun) continue; } - nLastTimeChanged = GetTimeMillis(); LogPrintf("CDarksendPool::DoAutomaticDenominating -- attempt %d connection to Masternode %s\n", nTries, pmn->addr.ToString()); CNode* pnode = ConnectNode((CAddress)pmn->addr, NULL, true); if(pnode) { @@ -1637,6 +1581,8 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun) LogPrintf("CDarksendPool::DoAutomaticDenominating -- connected, sending DSACCEPT, nSessionDenom: %d (%s)\n", nSessionDenom, GetDenominationsToString(nSessionDenom)); strAutoDenomResult = _("Mixing in progress..."); + nLastTimeChanged = GetTimeMillis(); + SetState(POOL_STATE_QUEUE); return true; } else { LogPrintf("CDarksendPool::DoAutomaticDenominating -- can't connect, addr=%s\n", pmn->addr.ToString()); @@ -2027,63 +1973,97 @@ bool CDarksendPool::IsOutputsCompatibleWithSessionDenom(const std::vector vecBits; + if(!GetDenominationsBits(nDenom, vecBits)) { + LogPrint("privatesend", "CDarksendPool::IsAcceptableDenomAndCollateral -- denom not valid!\n"); nMessageIDRet = ERR_DENOM; return false; } - LogPrintf("CDarksendPool::IsDenomCompatibleWithSession -- nSessionDenom: %d (%s) nSessionUsers: %d\n", - nSessionDenom, GetDenominationsToString(nSessionDenom), nSessionUsers); - + // check collateral if(!fUnitTest && !IsCollateralValid(txCollateral)) { - LogPrint("privatesend", "CDarksendPool::IsDenomCompatibleWithSession -- collateral not valid!\n"); + LogPrint("privatesend", "CDarksendPool::IsAcceptableDenomAndCollateral -- collateral not valid!\n"); nMessageIDRet = ERR_INVALID_COLLATERAL; return false; } - if(nSessionUsers < 0) nSessionUsers = 0; + return true; +} - if(nSessionUsers == 0) { - nMessageIDRet = MSG_NOERR; - nSessionID = GetInsecureRand(999999)+1; - nSessionDenom = nDenom; - nSessionUsers++; - nLastTimeChanged = GetTimeMillis(); +bool CDarksendPool::CreateNewSession(int nDenom, CTransaction txCollateral, PoolMessage& nMessageIDRet) +{ + if(!fMasterNode || nSessionID != 0) return false; - if(!fUnitTest) { - //broadcast that I'm accepting entries, only if it's the first entry through - CDarksendQueue dsq(nDenom, activeMasternode.vin, GetTime(), false); - LogPrint("privatesend", "CDarksendPool::IsDenomCompatibleWithSession -- signing and relaying new queue: %s\n", dsq.ToString()); - dsq.Sign(); - dsq.Relay(); - } - - SetState(POOL_STATE_QUEUE); - vecSessionCollaterals.push_back(txCollateral); - return true; + // new session can only be started in idle mode + if(nState != POOL_STATE_IDLE) { + nMessageIDRet = ERR_MODE; + LogPrintf("CDarksendPool::CreateNewSession -- incompatible mode: nState=%d\n", nState); + return false; } - if((nState != POOL_STATE_ACCEPTING_ENTRIES && nState != POOL_STATE_QUEUE) || nSessionUsers >= GetMaxPoolTransactions()) { - if((nState != POOL_STATE_ACCEPTING_ENTRIES && nState != POOL_STATE_QUEUE)) nMessageIDRet = ERR_MODE; - if(nSessionUsers >= GetMaxPoolTransactions()) nMessageIDRet = ERR_QUEUE_FULL; - LogPrintf("CDarksendPool::IsDenomCompatibleWithSession -- incompatible mode, return false: nState status %d, nSessionUsers status %d\n", nState != POOL_STATE_ACCEPTING_ENTRIES, nSessionUsers >= GetMaxPoolTransactions()); + if(!IsAcceptableDenomAndCollateral(nDenom, txCollateral, nMessageIDRet)) { + return false; + } + + // start new session + nMessageIDRet = MSG_NOERR; + nSessionID = GetInsecureRand(999999)+1; + nSessionDenom = nDenom; + nLastTimeChanged = GetTimeMillis(); + + if(!fUnitTest) { + //broadcast that I'm accepting entries, only if it's the first entry through + CDarksendQueue dsq(nDenom, activeMasternode.vin, GetTime(), false); + LogPrint("privatesend", "CDarksendPool::CreateNewSession -- signing and relaying new queue: %s\n", dsq.ToString()); + dsq.Sign(); + dsq.Relay(); + vecDarksendQueue.push_back(dsq); + } + + SetState(POOL_STATE_QUEUE); + vecSessionCollaterals.push_back(txCollateral); + LogPrintf("CDarksendPool::CreateNewSession -- new session created, nSessionID: %d nSessionDenom: %d (%s) vecSessionCollaterals.size(): %d\n", + nSessionID, nSessionDenom, GetDenominationsToString(nSessionDenom), vecSessionCollaterals.size()); + + return true; +} + +bool CDarksendPool::AddUserToExistingSession(int nDenom, CTransaction txCollateral, PoolMessage& nMessageIDRet) +{ + if(!fMasterNode || nSessionID == 0 || IsSessionReady()) return false; + + if(!IsAcceptableDenomAndCollateral(nDenom, txCollateral, nMessageIDRet)) { + return false; + } + + // we only add new users to an existing session when we are in queue mode + if(nState != POOL_STATE_QUEUE) { + nMessageIDRet = ERR_MODE; + LogPrintf("CDarksendPool::AddUserToExistingSession -- incompatible mode: nState=%d\n", nState); return false; } if(nDenom != nSessionDenom) { + LogPrintf("CDarksendPool::AddUserToExistingSession -- incompatible denom %d (%s) != nSessionDenom %d (%s)\n", + nDenom, GetDenominationsToString(nDenom), nSessionDenom, GetDenominationsToString(nSessionDenom)); nMessageIDRet = ERR_DENOM; return false; } - LogPrintf("CDarksendPool::IsDenomCompatibleWithSession -- compatible\n"); + // count new user as accepted to an existing session nMessageIDRet = MSG_NOERR; - nSessionUsers++; nLastTimeChanged = GetTimeMillis(); vecSessionCollaterals.push_back(txCollateral); + LogPrintf("CDarksendPool::AddUserToExistingSession -- new user accepted, nSessionID: %d nSessionDenom: %d (%s) vecSessionCollaterals.size(): %d\n", + nSessionID, nSessionDenom, GetDenominationsToString(nSessionDenom), vecSessionCollaterals.size()); + return true; } @@ -2423,12 +2403,6 @@ void CDarksendPool::SetState(PoolState nStateNew) } LogPrintf("CDarksendPool::SetState -- nState: %d, nStateNew: %d\n", nState, nStateNew); - if(nState != nStateNew) { - nLastTimeChanged = GetTimeMillis(); - if(fMasterNode) { - RelayStatus(STATUS_SET_STATE); - } - } nState = nStateNew; } diff --git a/src/darksend.h b/src/darksend.h index 45c4cfa32..30f6c8f6f 100644 --- a/src/darksend.h +++ b/src/darksend.h @@ -19,7 +19,7 @@ static const int PRIVATESEND_QUEUE_TIMEOUT = 30; static const int PRIVATESEND_SIGNING_TIMEOUT = 15; //! minimum peer version accepted by mixing pool -static const int MIN_PRIVATESEND_PEER_PROTO_VERSION = 70202; +static const int MIN_PRIVATESEND_PEER_PROTO_VERSION = 70203; static const CAmount PRIVATESEND_COLLATERAL = 0.001 * COIN; static const CAmount PRIVATESEND_POOL_MAX = 999.999 * COIN; @@ -95,21 +95,15 @@ public: std::vector vecTxDSIn; std::vector vecTxDSOut; CTransaction txCollateral; - CAmount nAmount; // depreciated since 12.1, it's used for backwards compatibility only and can be removed with future protocol bump - int64_t nTimeAdded; // time in UTC milliseconds CDarkSendEntry() : vecTxDSIn(std::vector()), vecTxDSOut(std::vector()), - txCollateral(CTransaction()), - nAmount(0), - nTimeAdded(GetTime()) + txCollateral(CTransaction()) {} CDarkSendEntry(const std::vector& vecTxIn, const std::vector& vecTxOut, const CTransaction& txCollateral) : - txCollateral(txCollateral), - nAmount(0), - nTimeAdded(GetTime()) + txCollateral(txCollateral) { BOOST_FOREACH(CTxIn txin, vecTxIn) vecTxDSIn.push_back(txin); @@ -122,14 +116,11 @@ public: template inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { READWRITE(vecTxDSIn); - READWRITE(nAmount); READWRITE(txCollateral); READWRITE(vecTxDSOut); } bool AddScriptSig(const CTxIn& txin); - - bool IsExpired() { return GetTime() - nTimeAdded > PRIVATESEND_QUEUE_TIMEOUT; } }; @@ -292,24 +283,20 @@ private: // pool states enum PoolState { - POOL_STATE_UNKNOWN, POOL_STATE_IDLE, POOL_STATE_QUEUE, POOL_STATE_ACCEPTING_ENTRIES, - POOL_STATE_FINALIZE_TRANSACTION, POOL_STATE_SIGNING, - POOL_STATE_TRANSMISSION, POOL_STATE_ERROR, POOL_STATE_SUCCESS, - POOL_STATE_MIN = POOL_STATE_UNKNOWN, + POOL_STATE_MIN = POOL_STATE_IDLE, POOL_STATE_MAX = POOL_STATE_SUCCESS }; // status update message constants enum PoolStatusUpdate { - STATUS_SET_STATE = -1, - STATUS_REJECTED = 0, - STATUS_ACCEPTED = 1 + STATUS_REJECTED, + STATUS_ACCEPTED }; mutable CCriticalSection cs_darksend; @@ -333,9 +320,7 @@ private: int nMinBlockSpacing; //required blocks between mixes const CBlockIndex *pCurrentBlockIndex; // Keep track of current block index - int nSessionID; - int nSessionUsers; //N Users have said they'll join - bool fSessionFoundMasternode; //If we've found a compatible Masternode + int nSessionID; // 0 if no mixing session is active int nEntriesCount; bool fLastEntryAccepted; @@ -374,10 +359,12 @@ private: /// Get the maximum number of transactions for the pool int GetMaxPoolTransactions() { return Params().PoolMaxTransactions(); } - /// Are these outputs compatible with other client in the pool? - bool IsOutputsCompatibleWithSessionDenom(const std::vector& vecTxDSOut); - /// Is this nDenom compatible with other client in the pool? - bool IsDenomCompatibleWithSession(int nDenom, CTransaction txCollateral, PoolMessage &nMessageIDRet); + /// Is this nDenom and txCollateral acceptable? + bool IsAcceptableDenomAndCollateral(int nDenom, CTransaction txCollateral, PoolMessage &nMessageIDRet); + bool CreateNewSession(int nDenom, CTransaction txCollateral, PoolMessage &nMessageIDRet); + bool AddUserToExistingSession(int nDenom, CTransaction txCollateral, PoolMessage &nMessageIDRet); + /// Do we have enough users to take entries? + bool IsSessionReady() { return (int)vecSessionCollaterals.size() >= GetMaxPoolTransactions(); } /// If the collateral is valid given by a client bool IsCollateralValid(const CTransaction& txCollateral); @@ -385,13 +372,13 @@ private: bool IsSignaturesComplete(); /// Check to make sure a given input matches an input in the pool and its scriptSig is valid bool IsInputScriptSigValid(const CTxIn& txin); + /// Are these outputs compatible with other client in the pool? + bool IsOutputsCompatibleWithSessionDenom(const std::vector& vecTxDSOut); bool IsDenomSkipped(CAmount nDenomValue) { return std::find(vecDenominationsSkipped.begin(), vecDenominationsSkipped.end(), nDenomValue) != vecDenominationsSkipped.end(); } - bool IsNull() const { return nState == POOL_STATE_ACCEPTING_ENTRIES && vecEntries.empty(); } - /// Create denominations bool CreateDenominated(); bool CreateDenominated(const CompactTallyItem& tallyItem); @@ -421,9 +408,11 @@ private: void RelayInAnon(std::vector& vin, std::vector& vout); void RelayIn(const CDarkSendEntry& entry); void PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID); - void RelayStatus(PoolStatusUpdate nStatusUpdate = STATUS_SET_STATE, PoolMessage nMessageID = MSG_NOERR); + void RelayStatus(PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID = MSG_NOERR); void RelayCompletedTransaction(PoolMessage nMessageID); + void SetNull(); + public: CMasternode* pSubmittedToMasternode; int nSessionDenom; //Users must submit an denom matching this @@ -466,7 +455,6 @@ public: void SetMinBlockSpacing(int nMinBlockSpacingIn) { nMinBlockSpacing = nMinBlockSpacingIn; } void ResetPool(); - void SetNull(); void UnlockCoins(); @@ -481,8 +469,6 @@ public: void CheckTimeout(); void CheckForCompleteQueue(); - /// Do we have enough users to take entries? - bool IsSessionReady(){ return nSessionUsers >= GetMaxPoolTransactions(); } /// Process a new block void NewBlock(); From 6695a43b4abd838e34fc8cb7d3a9b5ac9a611875 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Thu, 10 Nov 2016 01:49:57 +0300 Subject: [PATCH 2/4] rename nLastTimeChanged to nTimeLastSuccessfulStep, set state before updating nTimeLastSuccessfulStep --- src/darksend.cpp | 27 ++++++++++++++------------- src/darksend.h | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/darksend.cpp b/src/darksend.cpp index c8fbd341a..85fff5a3b 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -470,7 +470,7 @@ void CDarksendPool::SetNull() vecEntries.clear(); finalMutableTransaction.vin.clear(); finalMutableTransaction.vout.clear(); - nLastTimeChanged = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTimeMillis(); } // @@ -562,7 +562,7 @@ void CDarksendPool::CheckPool() } // reset if we're here for 10 seconds - if((nState == POOL_STATE_ERROR || nState == POOL_STATE_SUCCESS) && GetTimeMillis() - nLastTimeChanged >= 10000) { + if((nState == POOL_STATE_ERROR || nState == POOL_STATE_SUCCESS) && GetTimeMillis() - nTimeLastSuccessfulStep >= 10000) { LogPrint("privatesend", "CDarksendPool::CheckPool -- timeout, RESETTING\n"); UnlockCoins(); SetNull(); @@ -787,7 +787,7 @@ void CDarksendPool::CheckTimeout() int nLagTime = fMasterNode ? 0 : 10000; // if we're the client, give the server a few extra seconds before resetting. int nTimeout = (nState == POOL_STATE_SIGNING) ? PRIVATESEND_SIGNING_TIMEOUT : PRIVATESEND_QUEUE_TIMEOUT; - bool fTimeout = GetTimeMillis() - nLastTimeChanged >= nTimeout*1000 + nLagTime; + bool fTimeout = GetTimeMillis() - nTimeLastSuccessfulStep >= nTimeout*1000 + nLagTime; if(nState != POOL_STATE_IDLE && fTimeout) { LogPrint("privatesend", "CDarksendPool::CheckTimeout -- %s timed out (%ds) -- restting\n", @@ -962,7 +962,7 @@ bool CDarksendPool::AddEntry(const CDarkSendEntry& entryNew, PoolMessage& nMessa LogPrint("privatesend", "CDarksendPool::AddEntry -- adding entry\n"); nMessageIDRet = MSG_ENTRIES_ADDED; - nLastTimeChanged = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTimeMillis(); return true; } @@ -1090,7 +1090,7 @@ bool CDarksendPool::SendDenominate(const std::vector& vecTxIn, const std: CDarkSendEntry entry(vecTxIn, vecTxOut, txMyCollateral); vecEntries.push_back(entry); RelayIn(entry); - nLastTimeChanged = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTimeMillis(); return true; } @@ -1119,13 +1119,13 @@ bool CDarksendPool::UpdatePoolStateOnClient(PoolState nStateNew, int nEntriesCou if(nStateNew == POOL_STATE_QUEUE && nSessionID == 0 && nSessionIDNew != 0) { // new session id should be set only in POOL_STATE_QUEUE state nSessionID = nSessionIDNew; - nLastTimeChanged = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTimeMillis(); LogPrintf("CDarksendPool::UpdatePoolStateOnClient -- set nSessionID to %d\n", nSessionID); return true; } else if(nStateNew == POOL_STATE_ACCEPTING_ENTRIES && nEntriesCount != nEntriesCountNew) { nEntriesCount = nEntriesCountNew; - nLastTimeChanged = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTimeMillis(); fLastEntryAccepted = true; LogPrintf("CDarksendPool::UpdatePoolStateOnClient -- new entry accepted!\n"); return true; @@ -1219,8 +1219,8 @@ bool CDarksendPool::SignFinalTransaction(const CTransaction& finalTransactionNew // push all of our signatures to the Masternode LogPrintf("CDarksendPool::SignFinalTransaction -- pushing sigs to the masternode, finalMutableTransaction=%s", finalMutableTransaction.ToString()); pnode->PushMessage(NetMsgType::DSSIGNFINALTX, sigs); - nLastTimeChanged = GetTimeMillis(); SetState(POOL_STATE_SIGNING); + nTimeLastSuccessfulStep = GetTimeMillis(); return true; } @@ -1528,8 +1528,8 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun) LogPrintf("CDarksendPool::DoAutomaticDenominating -- connected (from queue), sending DSACCEPT: nSessionDenom: %d (%s), addr=%s\n", nSessionDenom, GetDenominationsToString(nSessionDenom), pnode->addr.ToString()); strAutoDenomResult = _("Mixing in progress..."); - nLastTimeChanged = GetTimeMillis(); SetState(POOL_STATE_QUEUE); + nTimeLastSuccessfulStep = GetTimeMillis(); return true; } else { LogPrintf("CDarksendPool::DoAutomaticDenominating -- can't connect, addr=%s\n", pmn->addr.ToString()); @@ -1581,8 +1581,8 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun) LogPrintf("CDarksendPool::DoAutomaticDenominating -- connected, sending DSACCEPT, nSessionDenom: %d (%s)\n", nSessionDenom, GetDenominationsToString(nSessionDenom)); strAutoDenomResult = _("Mixing in progress..."); - nLastTimeChanged = GetTimeMillis(); SetState(POOL_STATE_QUEUE); + nTimeLastSuccessfulStep = GetTimeMillis(); return true; } else { LogPrintf("CDarksendPool::DoAutomaticDenominating -- can't connect, addr=%s\n", pmn->addr.ToString()); @@ -2014,7 +2014,9 @@ bool CDarksendPool::CreateNewSession(int nDenom, CTransaction txCollateral, Pool nMessageIDRet = MSG_NOERR; nSessionID = GetInsecureRand(999999)+1; nSessionDenom = nDenom; - nLastTimeChanged = GetTimeMillis(); + + SetState(POOL_STATE_QUEUE); + nTimeLastSuccessfulStep = GetTimeMillis(); if(!fUnitTest) { //broadcast that I'm accepting entries, only if it's the first entry through @@ -2025,7 +2027,6 @@ bool CDarksendPool::CreateNewSession(int nDenom, CTransaction txCollateral, Pool vecDarksendQueue.push_back(dsq); } - SetState(POOL_STATE_QUEUE); vecSessionCollaterals.push_back(txCollateral); LogPrintf("CDarksendPool::CreateNewSession -- new session created, nSessionID: %d nSessionDenom: %d (%s) vecSessionCollaterals.size(): %d\n", nSessionID, nSessionDenom, GetDenominationsToString(nSessionDenom), vecSessionCollaterals.size()); @@ -2058,7 +2059,7 @@ bool CDarksendPool::AddUserToExistingSession(int nDenom, CTransaction txCollater // count new user as accepted to an existing session nMessageIDRet = MSG_NOERR; - nLastTimeChanged = GetTimeMillis(); + nTimeLastSuccessfulStep = GetTimeMillis(); vecSessionCollaterals.push_back(txCollateral); LogPrintf("CDarksendPool::AddUserToExistingSession -- new user accepted, nSessionID: %d nSessionDenom: %d (%s) vecSessionCollaterals.size(): %d\n", diff --git a/src/darksend.h b/src/darksend.h index 30f6c8f6f..ef2340deb 100644 --- a/src/darksend.h +++ b/src/darksend.h @@ -314,7 +314,7 @@ private: std::vector vecEntries; // Masternode/clients entries PoolState nState; // should be one of the POOL_STATE_XXX values - int64_t nLastTimeChanged; // last time the 'state' changed, in UTC milliseconds + int64_t nTimeLastSuccessfulStep; // the time when last successful mixing step was performed, in UTC milliseconds int nCachedLastSuccessBlock; int nMinBlockSpacing; //required blocks between mixes From 643798b5a9ade5314fe8bdb60b75fc088ca5ed35 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Fri, 11 Nov 2016 11:28:35 +0300 Subject: [PATCH 3/4] rename UpdatePoolStateOnClient to CheckPoolStateUpdate --- src/darksend.cpp | 13 +++++++------ src/darksend.h | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/darksend.cpp b/src/darksend.cpp index 85fff5a3b..6a5fef198 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -312,13 +312,14 @@ void CDarksendPool::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataS if(nMsgMessageID < MSG_POOL_MIN || nMsgMessageID > MSG_POOL_MAX) { LogPrint("privatesend", "DSSTATUSUPDATE -- nMsgMessageID is out of bounds: %d\n", nMsgMessageID); + if(pfrom->nVersion < 70203) nMsgMessageID = MSG_NOERR; return; } LogPrint("privatesend", "DSSTATUSUPDATE -- GetMessageByID: %s\n", GetMessageByID(PoolMessage(nMsgMessageID))); - if(!UpdatePoolStateOnClient(PoolState(nMsgState), nMsgEntriesCount, PoolStatusUpdate(nMsgStatusUpdate), PoolMessage(nMsgMessageID), nMsgSessionID)) { - LogPrint("privatesend", "DSSTATUSUPDATE -- can't update local state\n"); + if(!CheckPoolStateUpdate(PoolState(nMsgState), nMsgEntriesCount, PoolStatusUpdate(nMsgStatusUpdate), PoolMessage(nMsgMessageID), nMsgSessionID)) { + LogPrint("privatesend", "DSSTATUSUPDATE -- CheckPoolStateUpdate failed\n"); } } else if(strCommand == NetMsgType::DSSIGNFINALTX) { @@ -1096,7 +1097,7 @@ bool CDarksendPool::SendDenominate(const std::vector& vecTxIn, const std: } // Incoming message from Masternode updating the progress of mixing -bool CDarksendPool::UpdatePoolStateOnClient(PoolState nStateNew, int nEntriesCountNew, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, int nSessionIDNew) +bool CDarksendPool::CheckPoolStateUpdate(PoolState nStateNew, int nEntriesCountNew, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, int nSessionIDNew) { if(fMasterNode) return false; @@ -1107,7 +1108,7 @@ bool CDarksendPool::UpdatePoolStateOnClient(PoolState nStateNew, int nEntriesCou // if rejected at any state if(nStatusUpdate == STATUS_REJECTED) { - LogPrintf("CDarksendPool::UpdatePoolStateOnClient -- entry is rejected by Masternode\n"); + LogPrintf("CDarksendPool::CheckPoolStateUpdate -- entry is rejected by Masternode\n"); UnlockCoins(); SetNull(); SetState(POOL_STATE_ERROR); @@ -1120,14 +1121,14 @@ bool CDarksendPool::UpdatePoolStateOnClient(PoolState nStateNew, int nEntriesCou // new session id should be set only in POOL_STATE_QUEUE state nSessionID = nSessionIDNew; nTimeLastSuccessfulStep = GetTimeMillis(); - LogPrintf("CDarksendPool::UpdatePoolStateOnClient -- set nSessionID to %d\n", nSessionID); + LogPrintf("CDarksendPool::CheckPoolStateUpdate -- set nSessionID to %d\n", nSessionID); return true; } else if(nStateNew == POOL_STATE_ACCEPTING_ENTRIES && nEntriesCount != nEntriesCountNew) { nEntriesCount = nEntriesCountNew; nTimeLastSuccessfulStep = GetTimeMillis(); fLastEntryAccepted = true; - LogPrintf("CDarksendPool::UpdatePoolStateOnClient -- new entry accepted!\n"); + LogPrintf("CDarksendPool::CheckPoolStateUpdate -- new entry accepted!\n"); return true; } } diff --git a/src/darksend.h b/src/darksend.h index ef2340deb..4b72d7fd9 100644 --- a/src/darksend.h +++ b/src/darksend.h @@ -395,7 +395,7 @@ private: bool SendDenominate(const std::vector& vecTxIn, const std::vector& vecTxOut); /// Get Masternode updates about the progress of mixing - bool UpdatePoolStateOnClient(PoolState nStateNew, int nEntriesCountNew, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, int nSessionIDNew=0); + bool CheckPoolStateUpdate(PoolState nStateNew, int nEntriesCountNew, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, int nSessionIDNew=0); // Set the 'state' value, with some logging and capturing when the state changed void SetState(PoolState nStateNew); From 4b4921d8ce226f539c58593db3562805aeb3c721 Mon Sep 17 00:00:00 2001 From: UdjinM6 Date: Fri, 11 Nov 2016 11:29:13 +0300 Subject: [PATCH 4/4] reset pSubmittedToMasternode in SetNull() --- src/darksend.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/darksend.cpp b/src/darksend.cpp index 6a5fef198..dd2f36907 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -463,6 +463,7 @@ void CDarksendPool::SetNull() // Client side nEntriesCount = 0; fLastEntryAccepted = false; + pSubmittedToMasternode = NULL; // Both sides nState = POOL_STATE_IDLE;