fix - ds can leak info by number of inputs

This commit is contained in:
UdjinM6 2015-08-21 18:58:56 +03:00
parent 0002fd1d6e
commit f98fe6a208
5 changed files with 152 additions and 95 deletions

View File

@ -67,8 +67,22 @@ void CDarksendPool::ProcessMessageDarksend(CNode* pfrom, std::string& strCommand
}
int nDenom;
int nNumberOfInputs;
CTransaction txCollateral;
vRecv >> nDenom >> txCollateral;
vRecv >> nDenom >> nNumberOfInputs >> txCollateral;
//non-denom's are incompatible
if((nDenom & (1 << 4))) {
errorID = ERR_INVALID_DENOM;
pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID);
return;
}
if(nNumberOfInputs < DARKSEND_MIN_INPUTS || nNumberOfInputs > DARKSEND_MAX_INPUTS) {
errorID = ERR_INVALID_INPUTS_NUMBER;
pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID);
return;
}
CMasternode* pmn = mnodeman.Find(activeMasternode.vin);
if(pmn == NULL)
@ -88,13 +102,13 @@ void CDarksendPool::ProcessMessageDarksend(CNode* pfrom, std::string& strCommand
}
}
if(!IsCompatibleWithSession(nDenom, txCollateral, errorID))
if(!IsCompatibleWithSession(nDenom, nNumberOfInputs, txCollateral, errorID))
{
LogPrintf("dsa -- not compatible with existing transactions! \n");
LogPrintf("dsa -- not compatible with existing transactions!\n");
pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID);
return;
} else {
LogPrintf("dsa -- is compatible, please submit! \n");
LogPrintf("dsa -- is compatible, please submit!\n");
pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_ACCEPTED, errorID);
return;
}
@ -110,6 +124,15 @@ void CDarksendPool::ProcessMessageDarksend(CNode* pfrom, std::string& strCommand
CDarksendQueue dsq;
vRecv >> dsq;
//non-denom's are incompatible
if((dsq.nDenom & (1 << 4))) {
return;
}
if(dsq.nNumberOfInputs < DARKSEND_MIN_INPUTS || dsq.nNumberOfInputs > DARKSEND_MAX_INPUTS) {
return;
}
CService addr;
if(!dsq.GetAddress(addr)) return;
if(!dsq.CheckSignature()) return;
@ -173,10 +196,16 @@ void CDarksendPool::ProcessMessageDarksend(CNode* pfrom, std::string& strCommand
}
std::vector<CTxIn> in;
int64_t nAmount;
CTransaction txCollateral;
std::vector<CTxOut> out;
vRecv >> in >> nAmount >> txCollateral >> out;
vRecv >> in >> txCollateral >> out;
if((int)in.size() != sessionNumberOfInputs || (int)out.size() != sessionNumberOfInputs) {
errorID = ERR_INVALID_INPUTS_NUMBER;
pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, errorID);
return;
}
//do we have enough users in the current session?
if(!IsSessionReady()){
@ -270,7 +299,7 @@ void CDarksendPool::ProcessMessageDarksend(CNode* pfrom, std::string& strCommand
}
}
if(AddEntry(in, nAmount, txCollateral, out, errorID)){
if(AddEntry(in, txCollateral, out, errorID)){
pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_ACCEPTED, errorID);
Check();
@ -886,6 +915,7 @@ void CDarksendPool::CheckForCompleteQueue(){
CDarksendQueue dsq;
dsq.nDenom = sessionDenom;
dsq.nNumberOfInputs = sessionNumberOfInputs;
dsq.vin = activeMasternode.vin;
dsq.time = GetTime();
dsq.ready = true;
@ -992,11 +1022,11 @@ bool CDarksendPool::IsCollateralValid(const CTransaction& txCollateral){
//
// Add a clients transaction to the pool
//
bool CDarksendPool::AddEntry(const std::vector<CTxIn>& newInput, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector<CTxOut>& newOutput, int& errorID){
bool CDarksendPool::AddEntry(const std::vector<CTxIn>& newInput, const CTransaction& txCollateral, const std::vector<CTxOut>& newOutput, int& errorID){
if (!fMasterNode) return false;
BOOST_FOREACH(CTxIn in, newInput) {
if (in.prevout.IsNull() || nAmount < 0) {
if (in.prevout.IsNull()) {
LogPrint("darksend", "CDarksendPool::AddEntry - input not valid!\n");
errorID = ERR_INVALID_INPUT;
sessionUsers--;
@ -1033,7 +1063,7 @@ bool CDarksendPool::AddEntry(const std::vector<CTxIn>& newInput, const int64_t&
}
CDarkSendEntry v;
v.Add(newInput, nAmount, txCollateral, newOutput);
v.Add(newInput, txCollateral, newOutput);
entries.push_back(v);
LogPrint("darksend", "CDarksendPool::AddEntry -- adding %s\n", newInput[0].ToString());
@ -1094,7 +1124,7 @@ bool CDarksendPool::SignaturesComplete(){
// Execute a Darksend denomination via a Masternode.
// This is only ran from clients
//
void CDarksendPool::SendDarksendDenominate(std::vector<CTxIn>& vin, std::vector<CTxOut>& vout, int64_t amount){
void CDarksendPool::SendDarksendDenominate(std::vector<CTxIn>& vin, std::vector<CTxOut>& vout){
if(fMasterNode) {
LogPrintf("CDarksendPool::SendDarksendDenominate() - Darksend from a Masternode is not supported currently.\n");
@ -1141,13 +1171,10 @@ void CDarksendPool::SendDarksendDenominate(std::vector<CTxIn>& vin, std::vector<
//check it against the memory pool to make sure it's valid
{
int64_t nValueOut = 0;
CValidationState state;
CMutableTransaction tx;
BOOST_FOREACH(const CTxOut& o, vout){
nValueOut += o.nValue;
tx.vout.push_back(o);
}
@ -1174,10 +1201,10 @@ void CDarksendPool::SendDarksendDenominate(std::vector<CTxIn>& vin, std::vector<
// store our entry for later use
CDarkSendEntry e;
e.Add(vin, amount, txCollateral, vout);
e.Add(vin, txCollateral, vout);
entries.push_back(e);
RelayIn(entries[0].sev, entries[0].amount, txCollateral, entries[0].vout);
RelayIn(entries[0].sev, txCollateral, entries[0].vout);
Check();
}
@ -1525,6 +1552,8 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun)
//non-denom's are incompatible
if((dsq.nDenom & (1 << 4))) continue;
if(dsq.nNumberOfInputs < DARKSEND_MIN_INPUTS || dsq.nNumberOfInputs > DARKSEND_MAX_INPUTS) continue;
bool fUsed = false;
//don't reuse Masternodes
BOOST_FOREACH(CTxIn usedVin, vecMasternodesUsed){
@ -1538,11 +1567,16 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun)
std::vector<CTxIn> vTempCoins;
std::vector<COutput> vTempCoins2;
// Try to match their denominations if possible
if (!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, nValueMin, nBalanceNeedsAnonymized, vTempCoins, vTempCoins2, nValueIn, 0, nDarksendRounds)){
if (!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, dsq.nNumberOfInputs, vTempCoins, vTempCoins2, 0, nDarksendRounds)){
LogPrintf("DoAutomaticDenominating - Couldn't match denominations %d\n", dsq.nDenom);
continue;
}
if ((int)vTempCoins.size() < dsq.nNumberOfInputs) {
LogPrintf("DoAutomaticDenominating - Not enough denominations %d to match queue - %d %d\n", dsq.nDenom, (int)vTempCoins.size(), dsq.nNumberOfInputs);
continue;
}
// connect to Masternode and submit the queue request
CNode* pnode = ConnectNode((CAddress)addr, NULL, true);
if(pnode != NULL)
@ -1556,9 +1590,10 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun)
pSubmittedToMasternode = pmn;
vecMasternodesUsed.push_back(dsq.vin);
sessionDenom = dsq.nDenom;
sessionNumberOfInputs = dsq.nNumberOfInputs;
pnode->PushMessage("dsa", sessionDenom, txCollateral);
LogPrintf("DoAutomaticDenominating --- connected (from queue), sending dsa for %d - %s\n", sessionDenom, pnode->addr.ToString());
pnode->PushMessage("dsa", sessionDenom, sessionNumberOfInputs, txCollateral);
LogPrintf("DoAutomaticDenominating --- connected (from queue), sending dsa for essionNumberOfInputs %d sessionDenom %d - %s\n", sessionNumberOfInputs, sessionDenom, pnode->addr.ToString());
strAutoDenomResult = _("Mixing in progress...");
dsq.time = 0; //remove node
return true;
@ -1603,8 +1638,23 @@ bool CDarksendPool::DoAutomaticDenominating(bool fDryRun)
while(sessionDenom == 0)
sessionDenom = GetDenominationsByAmounts(vecAmounts);
pnode->PushMessage("dsa", sessionDenom, txCollateral);
LogPrintf("DoAutomaticDenominating --- connected, sending dsa for %d\n", sessionDenom);
std::vector<CTxIn> vTempCoins;
std::vector<COutput> vTempCoins2;
if (!pwalletMain->SelectCoinsByDenominations(sessionDenom, rand() % DARKSEND_MAX_INPUTS + 1, vTempCoins, vTempCoins2, 0, nDarksendRounds)){
// should never really happen
LogPrintf("DoAutomaticDenominating - Couldn't match denominations %d\n", sessionDenom);
continue;
}
if ((int)vTempCoins.size() < DARKSEND_MIN_INPUTS) {
LogPrintf("DoAutomaticDenominating - Not enough denominations to send %d\n", sessionDenom);
continue;
}
sessionNumberOfInputs = std::min(DARKSEND_MAX_INPUTS, (int)vTempCoins.size());
pnode->PushMessage("dsa", sessionDenom, sessionNumberOfInputs, txCollateral);
LogPrintf("DoAutomaticDenominating --- connected, sending dsa for sessionNumberOfInputs %d sessionDenom %d\n", sessionNumberOfInputs, sessionDenom);
strAutoDenomResult = _("Mixing in progress...");
return true;
} else {
@ -1818,16 +1868,18 @@ bool CDarksendPool::IsCompatibleWithEntries(std::vector<CTxOut>& vout)
LogPrintf(" vout 2 - %s\n", o2.ToString());
*/
if(GetDenominations(vout) != GetDenominations(v.vout)) return false;
if(vout.size() != v.vout.size()) return false;
}
return true;
}
bool CDarksendPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txCollateral, int& errorID)
bool CDarksendPool::IsCompatibleWithSession(int64_t nDenom, int nNumberOfInputs, CTransaction txCollateral, int& errorID)
{
if(nDenom == 0) return false;
LogPrintf("CDarksendPool::IsCompatibleWithSession - sessionDenom %d sessionUsers %d\n", sessionDenom, sessionUsers);
LogPrintf("CDarksendPool::IsCompatibleWithSession - sessionDenom %d sessionUsers %d nDenom %d nNumberOfInputs %d sessionNumberOfInputs %d\n",
sessionDenom, sessionUsers, nDenom, nNumberOfInputs, sessionNumberOfInputs);
if (!unitTest && !IsCollateralValid(txCollateral)){
LogPrint("darksend", "CDarksendPool::IsCompatibleWithSession - collateral not valid!\n");
@ -1841,12 +1893,14 @@ bool CDarksendPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txColla
sessionID = 1 + (rand() % 999999);
sessionDenom = nDenom;
sessionUsers++;
sessionNumberOfInputs = nNumberOfInputs;
lastTimeChanged = GetTimeMillis();
if(!unitTest){
//broadcast that I'm accepting entries, only if it's the first entry through
CDarksendQueue dsq;
dsq.nDenom = nDenom;
dsq.nNumberOfInputs = nNumberOfInputs;
dsq.vin = activeMasternode.vin;
dsq.time = GetTime();
dsq.Sign();
@ -1870,6 +1924,11 @@ bool CDarksendPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txColla
return false;
}
if(sessionNumberOfInputs != nNumberOfInputs) {
errorID = ERR_INVALID_INPUTS_NUMBER;
return false;
}
LogPrintf("CDarkSendPool::IsCompatibleWithSession - compatible\n");
sessionUsers++;
@ -2016,7 +2075,9 @@ std::string CDarksendPool::GetMessageByID(int messageID) {
case ERR_EXISTING_TX: return _("Not compatible with existing transactions.");
case ERR_FEES: return _("Transaction fees are too high.");
case ERR_INVALID_COLLATERAL: return _("Collateral not valid.");
case ERR_INVALID_DENOM: return _("Invalid denominations.");
case ERR_INVALID_INPUT: return _("Input is not valid.");
case ERR_INVALID_INPUTS_NUMBER: return _("Number of inputs is not valid.");
case ERR_INVALID_SCRIPT: return _("Invalid script detected.");
case ERR_INVALID_TX: return _("Transaction not valid.");
case ERR_MAXIMUM: return _("Value more than Darksend pool maximum allows.");
@ -2171,7 +2232,7 @@ void CDarksendPool::RelayFinalTransaction(const int sessionID, const CTransactio
}
}
void CDarksendPool::RelayIn(const std::vector<CTxDSIn>& vin, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector<CTxDSOut>& vout)
void CDarksendPool::RelayIn(const std::vector<CTxDSIn>& vin, const CTransaction& txCollateral, const std::vector<CTxDSOut>& vout)
{
if(!pSubmittedToMasternode) return;
@ -2187,7 +2248,7 @@ void CDarksendPool::RelayIn(const std::vector<CTxDSIn>& vin, const int64_t& nAmo
CNode* pnode = FindNode(pSubmittedToMasternode->addr);
if(pnode != NULL) {
LogPrintf("RelayIn - found master, relaying message - %s \n", pnode->addr.ToString());
pnode->PushMessage("dsi", vin2, nAmount, txCollateral, vout2);
pnode->PushMessage("dsi", vin2, txCollateral, vout2);
}
}

View File

@ -46,6 +46,9 @@ class CActiveMasternode;
#define DARKSEND_RELAY_OUT 2
#define DARKSEND_RELAY_SIG 3
#define DARKSEND_MIN_INPUTS 1
#define DARKSEND_MAX_INPUTS 5
static const int64_t DARKSEND_COLLATERAL = (0.01*COIN);
static const int64_t DARKSEND_POOL_MAX = (999.99*COIN);
@ -98,7 +101,6 @@ public:
bool isSet;
std::vector<CTxDSIn> sev;
std::vector<CTxDSOut> vout;
int64_t amount;
CTransaction collateral;
CTransaction txSupporting;
int64_t addedTime; // time in UTC milliseconds
@ -107,11 +109,10 @@ public:
{
isSet = false;
collateral = CTransaction();
amount = 0;
}
/// Add entries to use for Darksend
bool Add(const std::vector<CTxIn> vinIn, int64_t amountIn, const CTransaction collateralIn, const std::vector<CTxOut> voutIn)
bool Add(const std::vector<CTxIn> vinIn, const CTransaction collateralIn, const std::vector<CTxOut> voutIn)
{
if(isSet){return false;}
@ -121,7 +122,6 @@ public:
BOOST_FOREACH(const CTxOut& out, voutIn)
vout.push_back(out);
amount = amountIn;
collateral = collateralIn;
isSet = true;
addedTime = GetTime();
@ -161,12 +161,14 @@ public:
CTxIn vin;
int64_t time;
int nDenom;
int nNumberOfInputs;
bool ready; //ready for submit
std::vector<unsigned char> vchSig;
CDarksendQueue()
{
nDenom = 0;
nNumberOfInputs = 0;
vin = CTxIn();
time = 0;
vchSig.clear();
@ -178,6 +180,7 @@ public:
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(nDenom);
READWRITE(nNumberOfInputs);
READWRITE(vin);
READWRITE(time);
READWRITE(ready);
@ -301,7 +304,9 @@ public:
ERR_EXISTING_TX,
ERR_FEES,
ERR_INVALID_COLLATERAL,
ERR_INVALID_DENOM,
ERR_INVALID_INPUT,
ERR_INVALID_INPUTS_NUMBER,
ERR_INVALID_SCRIPT,
ERR_INVALID_TX,
ERR_MAXIMUM,
@ -324,6 +329,7 @@ public:
CMasternode* pSubmittedToMasternode;
int sessionDenom; //Users must submit an denom matching this
int sessionNumberOfInputs;//Users must submit only matching number of inputs
int cachedNumBlocks; //used for the overview screen
CDarksendPool()
@ -434,7 +440,7 @@ public:
bool IsCompatibleWithEntries(std::vector<CTxOut>& vout);
/// Is this amount compatible with other client in the pool?
bool IsCompatibleWithSession(int64_t nAmount, CTransaction txCollateral, int &errorID);
bool IsCompatibleWithSession(int64_t nAmount, int nNumberOfInputs, CTransaction txCollateral, int &errorID);
/// Passively run Darksend in the background according to the configuration in settings (only for QT)
bool DoAutomaticDenominating(bool fDryRun=false);
@ -454,13 +460,13 @@ public:
/// If the collateral is valid given by a client
bool IsCollateralValid(const CTransaction& txCollateral);
/// Add a clients entry to the pool
bool AddEntry(const std::vector<CTxIn>& newInput, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector<CTxOut>& newOutput, int& errorID);
bool AddEntry(const std::vector<CTxIn>& newInput, const CTransaction& txCollateral, const std::vector<CTxOut>& newOutput, int& errorID);
/// Add signature to a vin
bool AddScriptSig(const CTxIn& newVin);
/// Check that all inputs are signed. (Are all inputs signed?)
bool SignaturesComplete();
/// As a client, send a transaction to a Masternode to start the denomination process
void SendDarksendDenominate(std::vector<CTxIn>& vin, std::vector<CTxOut>& vout, int64_t amount);
void SendDarksendDenominate(std::vector<CTxIn>& vin, std::vector<CTxOut>& vout);
/// Get Masternode updates about the progress of Darksend
bool StatusUpdate(int newState, int newEntriesCount, int newAccepted, int &errorID, int newSessionID=0);
@ -499,7 +505,7 @@ public:
void RelayFinalTransaction(const int sessionID, const CTransaction& txNew);
void RelaySignaturesAnon(std::vector<CTxIn>& vin);
void RelayInAnon(std::vector<CTxIn>& vin, std::vector<CTxOut>& vout);
void RelayIn(const std::vector<CTxDSIn>& vin, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector<CTxDSOut>& vout);
void RelayIn(const std::vector<CTxDSIn>& vin, const CTransaction& txCollateral, const std::vector<CTxDSOut>& vout);
void RelayStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const int errorID=MSG_NOERR);
void RelayCompletedTransaction(const int sessionID, const bool error, const int errorID);
};

View File

@ -10,7 +10,7 @@
* network protocol versioning
*/
static const int PROTOCOL_VERSION = 70103;
static const int PROTOCOL_VERSION = 70104;
//! initial proto version, to be increased after version/verack negotiation
static const int INIT_PROTO_VERSION = 209;
@ -22,7 +22,7 @@ static const int GETHEADERS_VERSION = 70077;
static const int MIN_PEER_PROTO_VERSION = 70066;
//! minimum peer version accepted by DarksendPool
static const int MIN_POOL_PEER_PROTO_VERSION = 70103;
static const int MIN_POOL_PEER_PROTO_VERSION = 70104;
//! minimum peer version for masternode budgets
static const int MIN_BUDGET_PEER_PROTO_VERSION = 70103;

View File

@ -1787,11 +1787,9 @@ struct CompareByPriority
}
};
bool CWallet::SelectCoinsByDenominations(int nDenom, int64_t nValueMin, int64_t nValueMax, std::vector<CTxIn>& vCoinsRet, std::vector<COutput>& vCoinsRet2, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax)
bool CWallet::SelectCoinsByDenominations(int nDenom, int nNumberOfInputs, std::vector<CTxIn>& vCoinsRet, std::vector<COutput>& vCoinsRet2, int nDarksendRoundsMin, int nDarksendRoundsMax)
{
vCoinsRet.clear();
nValueRet = 0;
vCoinsRet2.clear();
vector<COutput> vCoins;
AvailableCoins(vCoins, true, NULL, ONLY_DENOMINATED);
@ -1814,53 +1812,44 @@ bool CWallet::SelectCoinsByDenominations(int nDenom, int64_t nValueMin, int64_t
{
// masternode-like input should not be selected by AvailableCoins now anyway
//if(out.tx->vout[out.i].nValue == 1000*COIN) continue;
if(nValueRet + out.tx->vout[out.i].nValue <= nValueMax){
bool fAccepted = false;
bool fAccepted = false;
// Function returns as follows:
//
// bit 0 - 100DRK+1 ( bit on if present )
// bit 1 - 10DRK+1
// bit 2 - 1DRK+1
// bit 3 - .1DRK+1
// Function returns as follows:
//
// bit 0 - 100DRK+1 ( bit on if present )
// bit 1 - 10DRK+1
// bit 2 - 1DRK+1
// bit 3 - .1DRK+1
CTxIn vin = CTxIn(out.tx->GetHash(),out.i);
CTxIn vin = CTxIn(out.tx->GetHash(),out.i);
int rounds = GetInputDarksendRounds(vin);
if(rounds >= nDarksendRoundsMax) continue;
if(rounds < nDarksendRoundsMin) continue;
int rounds = GetInputDarksendRounds(vin);
if(rounds >= nDarksendRoundsMax) continue;
if(rounds < nDarksendRoundsMin) continue;
if(fFound100 && fFound10 && fFound1 && fFoundDot1){ //if fulfilled
//we can return this for submission
if(nValueRet >= nValueMin){
//random reduce the max amount we'll submit for anonymity
nValueMax -= (rand() % (nValueMax/5));
//on average use 50% of the inputs or less
int r = (rand() % (int)vCoins.size());
if((int)vCoinsRet.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) +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) +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;
vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey
nValueRet += out.tx->vout[out.i].nValue;
vCoinsRet.push_back(vin);
vCoinsRet2.push_back(out);
if(fFound100 && fFound10 && fFound1 && fFoundDot1){ //if fulfilled
//we can return this for submission
if((int)vCoinsRet.size() >= nNumberOfInputs) 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) +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) +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;
vin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey
vCoinsRet.push_back(vin);
vCoinsRet2.push_back(out);
}
return (nValueRet >= nValueMin && fFound100 && fFound10 && fFound1 && fFoundDot1);
return ((int)vCoinsRet.size() >= nNumberOfInputs && fFound100 && fFound10 && fFound1 && fFoundDot1);
}
bool CWallet::SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector<CTxIn>& setCoinsRet, CAmount& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax) const
@ -2391,7 +2380,7 @@ int64_t CWallet::GetTotalValue(std::vector<CTxIn> vCoins) {
return nTotalValue;
}
string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
std::string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
{
if (IsLocked())
return _("Error: Wallet locked, unable to create transaction!");
@ -2404,7 +2393,6 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
std::vector<CTxIn> vCoins;
std::vector<CTxIn> vCoinsResult;
std::vector<COutput> vCoins2;
int64_t nValueIn = 0;
CReserveKey reservekey(this);
/*
@ -2413,11 +2401,17 @@ 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, vCoins2, nValueIn, minRounds, maxRounds))
if (!SelectCoinsByDenominations(darkSendPool.sessionDenom, darkSendPool.sessionNumberOfInputs, vCoins, vCoins2, minRounds, maxRounds))
return _("Error: Can't select current denominated inputs");
if ((int)vCoins.size() < darkSendPool.sessionNumberOfInputs) {
LogPrintf("PrepareDarksendDenominate - Not enough denominations %d to match queue - %d %d\n", darkSendPool.sessionDenom, (int)vCoins.size(), darkSendPool.sessionNumberOfInputs);
return "Error: Not enough denominations to match queue";
}
}
LogPrintf("PrepareDarksendDenominate - preparing darksend denominate . Got: %d \n", nValueIn);
LogPrintf("PrepareDarksendDenominate - preparing darksend denominate\n");
{
LOCK(cs_wallet);
@ -2425,20 +2419,18 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
LockCoin(v.prevout);
}
int64_t nValueLeft = nValueIn;
std::vector<CTxOut> vOut;
/*
TODO: Front load with needed denominations (e.g. .1, 1 )
*/
// Make outputs by looping through denominations: try to add every needed denomination, repeat up to 5-10 times.
// This way we can be pretty sure that it should have at least one of each needed denomination.
// Make outputs by looping through denominations: try to add needed denomination,
// repeat darkSendPool.sessionNumberOfInputs times.
// NOTE: No need to randomize order of inputs because they were
// initially shuffled in CWallet::SelectCoinsByDenominations already.
int nStep = 0;
int nStepsMax = 5 + GetRandInt(5);
while(nStep < nStepsMax) {
while(nStep < darkSendPool.sessionNumberOfInputs) {
BOOST_FOREACH(int64_t v, darkSendDenominations){
// only use the ones that are approved
@ -2450,7 +2442,7 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
if(!fAccepted) continue;
// try to add it
if(nValueLeft - v >= 0) {
if((int)vCoinsResult.size() < darkSendPool.sessionNumberOfInputs) {
// Note: this relies on a fact that both vectors MUST have same size
std::vector<CTxIn>::iterator it = vCoins.begin();
std::vector<COutput>::iterator it2 = vCoins2.begin();
@ -2475,7 +2467,6 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
vOut.push_back(o);
// subtract denomination amount
nValueLeft -= v;
break;
}
@ -2484,10 +2475,7 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
}
}
}
nStep++;
if(nValueLeft == 0) break;
}
{
@ -2497,7 +2485,9 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
UnlockCoin(v.prevout);
}
if(darkSendPool.GetDenominations(vOut) != darkSendPool.sessionDenom) {
if(darkSendPool.GetDenominations(vOut) != darkSendPool.sessionDenom ||
(int)vCoinsResult.size() != darkSendPool.sessionNumberOfInputs ||
(int)vOut.size() != darkSendPool.sessionNumberOfInputs) {
// unlock used coins on failure
LOCK(cs_wallet);
BOOST_FOREACH(CTxIn v, vCoinsResult)
@ -2509,7 +2499,7 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds)
std::random_shuffle (vOut.begin(), vOut.end());
// We also do not care about full amount as long as we have right denominations, just pass what we found
darkSendPool.SendDarksendDenominate(vCoinsResult, vOut, nValueIn - nValueLeft);
darkSendPool.SendDarksendDenominate(vCoinsResult, vOut);
return "";
}

View File

@ -149,7 +149,7 @@ private:
public:
// bool SelectCoins(int64_t nTargetValue, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, int64_t& nValueRet, const CCoinControl *coinControl = NULL, AvailableCoinsType coin_type=ALL_COINS, bool useIX = true) const;
bool SelectCoinsDark(int64_t nValueMin, int64_t nValueMax, std::vector<CTxIn>& setCoinsRet, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax) const;
bool SelectCoinsByDenominations(int nDenom, int64_t nValueMin, int64_t nValueMax, std::vector<CTxIn>& vCoinsRet, std::vector<COutput>& vCoinsRet2, int64_t& nValueRet, int nDarksendRoundsMin, int nDarksendRoundsMax);
bool SelectCoinsByDenominations(int nDenom, int nNumberOfInputs, std::vector<CTxIn>& vCoinsRet, std::vector<COutput>& vCoinsRet2, int nDarksendRoundsMin, int nDarksendRoundsMax);
bool SelectCoinsDarkDenominated(int64_t nTargetValue, std::vector<CTxIn>& setCoinsRet, int64_t& nValueRet) const;
bool HasCollateralInputs(bool fOnlyConfirmed = true) const;
bool IsCollateralAmount(int64_t nInputAmount) const;