diff --git a/src/darksend.cpp b/src/darksend.cpp index 98f4ff8c30..b350a49ef0 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -793,7 +793,7 @@ void CDarkSendPool::ChargeRandomFees(){ // Check for various timeouts (queue objects, darksend, etc) // void CDarkSendPool::CheckTimeout(){ - if(!fEnableDarksend) return; + if(!fEnableDarksend && !fMasterNode) return; // catching hanging sessions if(!fMasterNode) { @@ -2032,10 +2032,10 @@ int CDarkSendPool::GetDenominationsByAmount(int64_t nAmount, int nDenomTarget){ BOOST_REVERSE_FOREACH(int64_t v, darkSendDenominations){ if(nDenomTarget != 0){ bool fAccepted = false; - if((nDenomTarget & (1 << 0)) && v == ((100*COIN)+1)) {fAccepted = true;} - else if((nDenomTarget & (1 << 1)) && v == ((10*COIN)+1)) {fAccepted = true;} - else if((nDenomTarget & (1 << 2)) && v == ((1*COIN)+1)) {fAccepted = true;} - else if((nDenomTarget & (1 << 3)) && v == ((.1*COIN)+1)) {fAccepted = true;} + if((nDenomTarget & (1 << 0)) && v == ((100*COIN)+100000)) {fAccepted = true;} + else if((nDenomTarget & (1 << 1)) && v == ((10*COIN) +10000)) {fAccepted = true;} + else if((nDenomTarget & (1 << 2)) && v == ((1*COIN) +1000)) {fAccepted = true;} + else if((nDenomTarget & (1 << 3)) && v == ((.1*COIN) +100)) {fAccepted = true;} if(!fAccepted) continue; } diff --git a/src/init.cpp b/src/init.cpp index d821f822af..fafb5e32a2 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -1175,10 +1175,23 @@ bool AppInit2(boost::thread_group& threadGroup) LogPrintf("Darksend rounds %d\n", nDarksendRounds); LogPrintf("Anonymize Darkcoin Amount %d\n", nAnonymizeDarkcoinAmount); - darkSendDenominations.push_back( (100 * COIN)+1 ); - darkSendDenominations.push_back( (10 * COIN)+1 ); - darkSendDenominations.push_back( (1 * COIN)+1 ); - darkSendDenominations.push_back( (.1 * COIN)+1 ); + /* Denominations + + A note about convertability. Within Darksend pools, each denomination + is convertable to another. + + For example: + 1DRK+1000 == (.1DRK+100)*10 + 10DRK+10000 == (1DRK+1000)*10 + */ + darkSendDenominations.push_back( (100 * COIN)+100000 ); + darkSendDenominations.push_back( (10 * COIN)+10000 ); + darkSendDenominations.push_back( (1 * COIN)+1000 ); + darkSendDenominations.push_back( (.1 * COIN)+100 ); + /* Disabled till we need them + darkSendDenominations.push_back( (.01 * COIN)+10 ); + darkSendDenominations.push_back( (.001 * COIN)+1 ); + */ darkSendPool.InitCollateralAddress(); diff --git a/src/wallet.cpp b/src/wallet.cpp index df83e67722..79411828cb 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1468,9 +1468,9 @@ bool CWallet::SelectCoins(int64_t nTargetValue, setvout[out.i].nValue == v //make sure it's the denom we're looking for - && nValueRet + out.tx->vout[out.i].nValue < nTargetValue + (0.1*COIN)+1 //round the amount up to .1DRK over - && added <= 50){ //don't add more than 50 of one denom type + if(out.tx->vout[out.i].nValue == v //make sure it's the denom we're looking for + && nValueRet + out.tx->vout[out.i].nValue < nTargetValue + (0.1*COIN)+100 //round the amount up to .1DRK over + && added <= 50){ //don't add more than 50 of one denom type nValueRet += out.tx->vout[out.i].nValue; setCoinsRet.insert(make_pair(out.tx, out.i)); added++; @@ -1534,7 +1534,7 @@ bool CWallet::SelectCoinsByDenominations(int nDenom, int64_t nValueMin, int64_t BOOST_FOREACH(const COutput& out, vCoins) { //there's no reason to allow inputs less than 1 COIN into DS (other than denominations smaller than that amount) - if(out.tx->vout[out.i].nValue < 1*COIN && out.tx->vout[out.i].nValue != (.1*COIN)+1) continue; + if(out.tx->vout[out.i].nValue < 1*COIN && out.tx->vout[out.i].nValue != (.1*COIN)+100) continue; if(fMasterNode && out.tx->vout[out.i].nValue == 1000*COIN) continue; //masternode input if(nValueRet + out.tx->vout[out.i].nValue <= nValueMax){ bool fAccepted = false; @@ -1562,16 +1562,16 @@ bool CWallet::SelectCoinsByDenominations(int nDenom, int64_t nValueMin, int64_t if((int)setCoinsRet.size() > r) return true; } //Denomination criterion has been met, we can take any matching denominations - if((nDenom & (1 << 0)) && out.tx->vout[out.i].nValue == ((100*COIN)+1)) {fAccepted = true;} - else if((nDenom & (1 << 1)) && out.tx->vout[out.i].nValue == ((10*COIN)+1)) {fAccepted = true;} - else if((nDenom & (1 << 2)) && out.tx->vout[out.i].nValue == ((1*COIN)+1)) {fAccepted = true;} - else if((nDenom & (1 << 3)) && out.tx->vout[out.i].nValue == ((.1*COIN)+1)) {fAccepted = true;} + if((nDenom & (1 << 0)) && out.tx->vout[out.i].nValue == ((100*COIN) +100000)) {fAccepted = true;} + else if((nDenom & (1 << 1)) && out.tx->vout[out.i].nValue == ((10*COIN)+10000)) {fAccepted = true;} + else if((nDenom & (1 << 2)) && out.tx->vout[out.i].nValue == ((1*COIN) +1000)) {fAccepted = true;} + else if((nDenom & (1 << 3)) && out.tx->vout[out.i].nValue == ((.1*COIN)+100)) {fAccepted = true;} } else { //Criterion has not been satisfied, we will only take 1 of each until it is. - if((nDenom & (1 << 0)) && out.tx->vout[out.i].nValue == ((100*COIN)+1)) {fAccepted = true; fFound100 = true;} - else if((nDenom & (1 << 1)) && out.tx->vout[out.i].nValue == ((10*COIN)+1)) {fAccepted = true; fFound10 = true;} - else if((nDenom & (1 << 2)) && out.tx->vout[out.i].nValue == ((1*COIN)+1)) {fAccepted = true; fFound1 = true;} - else if((nDenom & (1 << 3)) && out.tx->vout[out.i].nValue == ((.1*COIN)+1)) {fAccepted = true; fFoundDot1 = true;} + if((nDenom & (1 << 0)) && out.tx->vout[out.i].nValue == ((100*COIN) +100000)) {fAccepted = true; fFound100 = true;} + else if((nDenom & (1 << 1)) && out.tx->vout[out.i].nValue == ((10*COIN)+10000)) {fAccepted = true; fFound10 = true;} + else if((nDenom & (1 << 2)) && out.tx->vout[out.i].nValue == ((1*COIN) +1000)) {fAccepted = true; fFound1 = true;} + else if((nDenom & (1 << 3)) && out.tx->vout[out.i].nValue == ((.1*COIN)+100)) {fAccepted = true; fFoundDot1 = true;} } if(!fAccepted) continue; @@ -1604,7 +1604,7 @@ bool CWallet::SelectCoinsDark(int64_t nValueMin, int64_t nValueMax, std::vector< BOOST_FOREACH(const COutput& out, vCoins) { //there's no reason to allow inputs less than 1 COIN into DS (other than denominations smaller than that amount) - if(out.tx->vout[out.i].nValue < 1*COIN && out.tx->vout[out.i].nValue != (.1*COIN)+1) continue; + if(out.tx->vout[out.i].nValue < 1*COIN && out.tx->vout[out.i].nValue != (.1*COIN)+100) continue; if(fMasterNode && out.tx->vout[out.i].nValue == 1000*COIN) continue; //masternode input if(nValueRet + out.tx->vout[out.i].nValue <= nValueMax){ @@ -2136,31 +2136,110 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds) // denominate our funds int64_t nValueLeft = nTotalValue; std::vector vOut; + std::vector vDenoms; - // Make outputs by looping through denominations, from small to large + /* + TODO: Front load with needed denominations (e.g. .1, 1 ) + */ - 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 all denominations once - CTxOut o(out.tx->vout[out.i].nValue, scriptChange); - vOut.push_back(o); + The beginning of the list is front loaded with each possible + denomination in random order. This means we'll at least get 1 + of each that is required as outputs. + */ + BOOST_FOREACH(int64_t d, darkSendDenominations){ + vDenoms.push_back(d); + vDenoms.push_back(d); + } - //increment outputs and subtract denomination amount - nValueLeft -= out.tx->vout[out.i].nValue; + //randomize the order of these denominations + std::random_shuffle (vDenoms.begin(), vDenoms.end()); + + /* + Build a long list of denominations + + Next we'll build a long random list of denominations to add. + Eventually as the algorithm goes through these it'll find the ones + it nees to get exact change. + */ + for(int i = 0; i <= 500; i++) + BOOST_FOREACH(int64_t d, darkSendDenominations) + vDenoms.push_back(d); + + //randomize the order of inputs we get back + std::random_shuffle (vDenoms.begin() + (int)darkSendDenominations.size() + 1, vDenoms.end()); + + // Make outputs by looping through denominations randomly + BOOST_REVERSE_FOREACH(int64_t v, vDenoms){ + //only use the ones that are approved + bool fAccepted = false; + if((darkSendPool.sessionDenom & (1 << 0)) && v == ((100*COIN) +100000)) {fAccepted = true;} + else if((darkSendPool.sessionDenom & (1 << 1)) && v == ((10*COIN) +10000)) {fAccepted = true;} + else if((darkSendPool.sessionDenom & (1 << 2)) && v == ((1*COIN) +1000)) {fAccepted = true;} + else if((darkSendPool.sessionDenom & (1 << 3)) && v == ((.1*COIN) +100)) {fAccepted = true;} + if(!fAccepted) continue; + + int nOutputs = 0; + + // add each output up to 10 times until it can't be added again + if(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(v, scriptChange); + vOut.push_back(o); + + //increment outputs and subtract denomination amount + nOutputs++; + nValueLeft -= v; + } if(nValueLeft == 0) break; } - // if we have anything left over, send it back as change + //back up mode , incase we couldn't successfully make the outputs for some reason + if(vOut.size() > 40 || darkSendPool.GetDenominations(vOut) != darkSendPool.sessionDenom || nValueLeft != 0){ + vOut.clear(); + nValueLeft = nTotalValue; + // Make outputs by looping through denominations, from small to large + + 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(); + + CTxOut o(out.tx->vout[out.i].nValue, scriptChange); + vOut.push_back(o); + + //increment outputs and subtract denomination amount + nValueLeft -= out.tx->vout[out.i].nValue; + + if(nValueLeft == 0) break; + } + + } + + if(darkSendPool.GetDenominations(vOut) != darkSendPool.sessionDenom) + return "Error: can't make current denominated outputs"; + + // we don't support change at all if(nValueLeft != 0) return "Error: change left-over in pool. Must use denominations only"; + + //randomize the output order + std::random_shuffle (vOut.begin(), vOut.end()); + darkSendPool.SendDarksendDenominate(vCoins, vOut, nValueIn); return "";