diff --git a/src/darksend.cpp b/src/darksend.cpp index 5e89a4130..98f4ff8c3 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -18,6 +18,7 @@ using namespace std; using namespace boost; +CCriticalSection cs_darksend; /** The main object for accessing darksend */ CDarkSendPool darkSendPool; @@ -461,7 +462,6 @@ void CDarkSendPool::SetNull(bool clearEverything){ sessionUsers = 0; sessionDenom = 0; sessionFoundMasternode = false; - sessionTries = 0; vecSessionCollateral.clear(); txCollateral = CTransaction(); @@ -864,7 +864,6 @@ void CDarkSendPool::CheckTimeout(){ sessionUsers = 0; sessionDenom = 0; sessionFoundMasternode = false; - sessionTries = 0; vecSessionCollateral.clear(); UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); @@ -1410,6 +1409,8 @@ void CDarkSendPool::ClearLastMessage() // bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) { + LOCK(cs_darksend); + if(fMasterNode) return false; if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) return false; @@ -1443,6 +1444,7 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) // ** find the coins we'll use std::vector vCoins; + std::vector vCoins2; int64_t nValueMin = 0.01*COIN; int64_t nValueIn = 0; int64_t lowestDenom = COIN*0.1; @@ -1456,8 +1458,7 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) int64_t nonanonymized = pwalletMain->GetBalance() - pwalletMain->GetAnonymizedBalance() - COIN; if(balanceNeedsAnonymized > nonanonymized) balanceNeedsAnonymized = nonanonymized; - if(balanceNeedsAnonymized < lowestDenom || - (vecDisabledDenominations.size() > 0 && balanceNeedsAnonymized < COIN*10)){ + if(balanceNeedsAnonymized < lowestDenom){ LogPrintf("DoAutomaticDenominating : No funds detected in need of denominating \n"); strAutoDenomResult = "No funds detected in need of denominating"; return false; @@ -1489,15 +1490,6 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) if(fDryRun) return true; - if(vecDisabledDenominations.size() == 0){ - //if we have 20x 0.1DRk and 1DRK inputs, we can start just anonymizing 10DRK inputs. - if(pwalletMain->CountInputsWithAmount((1 * COIN)+1) >= 20 && - pwalletMain->CountInputsWithAmount((.1 * COIN)+1) >= 20){ - vecDisabledDenominations.push_back((1 * COIN)+1); - vecDisabledDenominations.push_back((.1 * COIN)+1); - } - } - // initial phase, find a masternode if(!sessionFoundMasternode){ int nUseQueue = rand()%100; @@ -1542,11 +1534,9 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) } // Try to match their denominations if possible - if (!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nValueMin, balanceNeedsAnonymized, vCoins, nValueIn, 0, nDarksendRounds)){ -// if (!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nValueMin, balanceNeedsAnonymized, vCoins, nValueIn, -2, 0)){ - LogPrintf("DoAutomaticDenominating - Couldn't match denominations %d\n", dsq.nDenom); - continue; -// } + if (!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nValueMin, balanceNeedsAnonymized, vCoins, vCoins2, nValueIn, 0, nDarksendRounds)){ + LogPrintf("DoAutomaticDenominating - Couldn't match denominations %d\n", dsq.nDenom); + continue; } // connect to masternode and submit the queue request @@ -1584,30 +1574,33 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) } } - // otherwise, try one randomly - if(sessionTries++ < 10){ - //pick a random masternode to use - int max_value = vecMasternodes.size(); - if(max_value <= 0) return false; - int i = (rand() % max_value); + //shuffle masternodes around before we try to connect + std::random_shuffle ( vecMasternodes.begin(), vecMasternodes.end() ); + int i = 0; + // otherwise, try one randomly + while(i < 10) + { //don't reuse masternodes BOOST_FOREACH(CTxIn usedVin, vecMasternodesUsed) { if(vecMasternodes[i].vin == usedVin){ - return DoAutomaticDenominating(); + i++; + continue; } } if(vecMasternodes[i].protocolVersion < MIN_PEER_PROTO_VERSION) { - return DoAutomaticDenominating(); + i++; + continue; } if(vecMasternodes[i].nLastDsq != 0 && vecMasternodes[i].nLastDsq + CountMasternodesAboveProtocol(darkSendPool.MIN_PEER_PROTO_VERSION)/5 > darkSendPool.nDsqCount){ - return DoAutomaticDenominating(); + i++; + continue; } lastTimeChanged = GetTimeMillis(); - LogPrintf("DoAutomaticDenominating -- attempt %d connection to masternode %s\n", sessionTries, vecMasternodes[i].addr.ToString().c_str()); + LogPrintf("DoAutomaticDenominating -- attempt %d connection to masternode %s\n", i, vecMasternodes[i].addr.ToString().c_str()); if(ConnectNode((CAddress)vecMasternodes[i].addr, NULL, true)){ submittedToMasternode = vecMasternodes[i].addr; @@ -1619,7 +1612,7 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) std::string strReason; if(txCollateral == CTransaction()){ if(!pwalletMain->CreateCollateralTransaction(txCollateral, strReason)){ - LogPrintf("DoAutomaticDenominating -- dsa error:%s\n", strReason.c_str()); + LogPrintf("DoAutomaticDenominating -- create collateral error:%s\n", strReason.c_str()); return false; } } @@ -1636,13 +1629,13 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) return true; } } else { - LogPrintf("DoAutomaticDenominating --- error connecting \n"); - return DoAutomaticDenominating(); + i++; + continue; } - } else { - strAutoDenomResult = "No compatible masternode found"; - return false; } + + strAutoDenomResult = "No compatible masternode found"; + return false; } strAutoDenomResult = ""; @@ -1820,15 +1813,8 @@ bool CDarkSendPool::CreateDenominated(int64_t nTotalValue) // ****** Add denoms ************ / BOOST_REVERSE_FOREACH(int64_t v, darkSendDenominations){ - int nOutputs = 0; - if(std::find(vecDisabledDenominations.begin(), - vecDisabledDenominations.end(), v) != - vecDisabledDenominations.end()){ - continue; - } - // add each output up to 10 times until it can't be added again while(nValueLeft - v >= 0 && nOutputs <= 10) { CScript scriptChange; @@ -2055,9 +2041,6 @@ int CDarkSendPool::GetDenominationsByAmount(int64_t nAmount, int nDenomTarget){ int nOutputs = 0; - if(std::find(vecDisabledDenominations.begin(), vecDisabledDenominations.end(), v) != vecDisabledDenominations.end()) - continue; - // add each output up to 10 times until it can't be added again while(nValueLeft - v >= 0 && nOutputs <= 10) { CTxOut o(v, e); diff --git a/src/darksend.h b/src/darksend.h index f9a4a3beb..b281e20bf 100644 --- a/src/darksend.h +++ b/src/darksend.h @@ -256,7 +256,6 @@ public: int sessionDenom; //Users must submit an denom matching this int sessionUsers; //N Users have said they'll join bool sessionFoundMasternode; //If we've found a compatible masternode - int sessionTries; int64_t sessionTotalValue; //used for autoDenom std::vector vecSessionCollateral; @@ -270,8 +269,6 @@ public: //debugging data std::string strAutoDenomResult; - std::vector vecDisabledDenominations; - //incremented whenever a DSQ comes through int64_t nDsqCount; @@ -288,7 +285,6 @@ public: txCollateral = CTransaction(); minBlockSpacing = 1; nDsqCount = 0; - vecDisabledDenominations.clear(); SetNull(); } diff --git a/src/wallet.cpp b/src/wallet.cpp index 32def1e0e..df83e6772 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1505,18 +1505,17 @@ struct CompareByPriority } }; -bool CWallet::SelectCoinsByDenominations(int nDenom, int64_t nValueMin, int64_t nValueMax, std::vector& setCoinsRet, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax) +bool CWallet::SelectCoinsByDenominations(int nDenom, int64_t nValueMin, int64_t nValueMax, std::vector& setCoinsRet, vector& setCoinsRet2, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax) { CCoinControl *coinControl=NULL; setCoinsRet.clear(); nValueRet = 0; + setCoinsRet2.clear(); vector vCoins; AvailableCoins(vCoins, false, coinControl, ALL_COINS); - set > setCoinsRet2; - //order the array so fees are first, then denominated money, then the rest. std::random_shuffle(vCoins.rbegin(), vCoins.rend()); @@ -1579,7 +1578,7 @@ bool CWallet::SelectCoinsByDenominations(int nDenom, int64_t nValueMin, int64_t vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey nValueRet += out.tx->vout[out.i].nValue; setCoinsRet.push_back(vin); - setCoinsRet2.insert(make_pair(out.tx, out.i)); + setCoinsRet2.push_back(out); } } @@ -2112,6 +2111,7 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds) // ** find the coins we'll use std::vector vCoins; + std::vector vCoins2; int64_t nValueIn = 0; CReserveKey reservekey(this); @@ -2121,7 +2121,7 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds) if minRounds >= 0 it means only denominated inputs are going in and coming out */ if(minRounds >= 0){ - if (!SelectCoinsByDenominations(darkSendPool.sessionDenom, 0.1*COIN, DARKSEND_POOL_MAX, vCoins, nValueIn, minRounds, maxRounds)) + if (!SelectCoinsByDenominations(darkSendPool.sessionDenom, 0.1*COIN, DARKSEND_POOL_MAX, vCoins, vCoins2, nValueIn, minRounds, maxRounds)) return _("Insufficient funds"); } @@ -2138,48 +2138,28 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds) std::vector vOut; // Make outputs by looping through denominations, from small to large - BOOST_REVERSE_FOREACH(int64_t v, darkSendDenominations){ - bool fAccepted = false; - if((darkSendPool.sessionDenom & (1 << 0)) && v == ((100*COIN)+1)) {fAccepted = true;} - else if((darkSendPool.sessionDenom & (1 << 1)) && v == ((10*COIN)+1)) {fAccepted = true;} - else if((darkSendPool.sessionDenom & (1 << 2)) && v == ((1*COIN)+1)) {fAccepted = true;} - else if((darkSendPool.sessionDenom & (1 << 3)) && v == ((.1*COIN)+1)) {fAccepted = true;} - if(!fAccepted) continue; - int nOutputs = 0; + BOOST_FOREACH(const COutput& out, vCoins2){ + CScript scriptChange; + CPubKey vchPubKey; + //use a unique change address + assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked + scriptChange.SetDestination(vchPubKey.GetID()); + reservekey.KeepKey(); - // add each output up to 10 times until it can't be added again - while(nValueLeft - v >= 0 && nOutputs <= 10) { - CScript scriptChange; - CPubKey vchPubKey; - //use a unique change address - assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptChange.SetDestination(vchPubKey.GetID()); - reservekey.KeepKey(); + CTxOut o(out.tx->vout[out.i].nValue, scriptChange); + vOut.push_back(o); - CTxOut o(v, scriptChange); - vOut.push_back(o); - - //increment outputs and subtract denomination amount - nOutputs++; - nValueLeft -= v; - } + //increment outputs and subtract denomination amount + nValueLeft -= out.tx->vout[out.i].nValue; if(nValueLeft == 0) break; } // if we have anything left over, send it back as change - if(nValueLeft > 0){ - CScript scriptChange; - CPubKey vchPubKey; - assert(reservekey.GetReservedKey(vchPubKey)); // should never fail, as we just unlocked - scriptChange.SetDestination(vchPubKey.GetID()); - reservekey.KeepKey(); - - CTxOut o(nValueLeft, scriptChange); - vOut.push_back(o); - } + if(nValueLeft != 0) + return "Error: change left-over in pool. Must use denominations only"; darkSendPool.SendDarksendDenominate(vCoins, vOut, nValueIn); diff --git a/src/wallet.h b/src/wallet.h index 93f8baa38..2cb1f4cf5 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -133,7 +133,7 @@ private: public: bool SelectCoins(int64_t nTargetValue, std::set >& setCoinsRet, int64_t& nValueRet, const CCoinControl *coinControl = NULL, AvailableCoinsType coin_type=ALL_COINS) const; bool SelectCoinsDark(int64_t nValueMin, int64_t nValueMax, std::vector& setCoinsRet, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax) const; - bool SelectCoinsByDenominations(int nDenom, int64_t nValueMin, int64_t nValueMax, std::vector& setCoinsRet, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax); + bool SelectCoinsByDenominations(int nDenom, int64_t nValueMin, int64_t nValueMax, std::vector& setCoinsRet, vector& vCoins, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax); bool SelectCoinsDarkDenominated(int64_t nTargetValue, std::vector& setCoinsRet, int64_t& nValueRet) const; bool SelectCoinsMasternode(CTxIn& vin, int64_t& nValueRet, CScript& pubScript) const; bool HasDarksendFeeInputs() const;