mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Implemented DarkSend convertability
Darksend defaults to a new mode which enables inputs/outputs of each session to be different. For example 10DRK can be input and 1DRKx10 can be output. This strengthens the anonymity of Darksend greatly, which also increasing the usability (Users who run out of .1DRK denominations can simply turn on Darksend to split up larger inputs).
This commit is contained in:
parent
bbd869589c
commit
78fe35f06d
@ -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;
|
||||
}
|
||||
|
||||
|
21
src/init.cpp
21
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();
|
||||
|
||||
|
131
src/wallet.cpp
131
src/wallet.cpp
@ -1468,9 +1468,9 @@ bool CWallet::SelectCoins(int64_t nTargetValue, set<pair<const CWalletTx*,unsign
|
||||
int added = 0;
|
||||
BOOST_FOREACH(const COutput& out, vCoins)
|
||||
{
|
||||
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)+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<CTxOut> vOut;
|
||||
std::vector<int64_t> 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 "";
|
||||
|
Loading…
Reference in New Issue
Block a user