Refactor PrivateSend (#1735)

* make infoMixingMasternode private

* move PS queue entries expiration checks (and cs_darksend) to CPrivateSendBase

* drop CTxDSOut

* move prevPubKey out of CTxIn into CTxDSIn and use CTxDSIn explicitly

* drop CPrivateSendClient::NewBlock

* move IsDenominatedAmount to CPrivateSend

* move IsCollateralAmount to CPrivateSend

* drop darksend-relay.cpp/h

* drop GetMasternodeByRank
This commit is contained in:
UdjinM6 2017-12-04 09:06:07 +03:00 committed by GitHub
parent c166ed39b0
commit 7e96af4e65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 169 additions and 412 deletions

View File

@ -172,7 +172,7 @@ When queue is ready user is expected to send his entry to start actual mixing
| ? | vecTxDSIn | CTxDSIn[] | vector of users inputs (CTxDSIn serialization is equal to [CTxIn](#ctxin) serialization) | ? | vecTxDSIn | CTxDSIn[] | vector of users inputs (CTxDSIn serialization is equal to [CTxIn](#ctxin) serialization)
| 8 | nAmount | int64_t | depreciated since 12.1, it's used for backwards compatibility only and can be removed with future protocol bump | 8 | nAmount | int64_t | depreciated since 12.1, it's used for backwards compatibility only and can be removed with future protocol bump
| ? | txCollateral | [CTransaction](#ctransaction) | Collateral transaction which is used to prevent misbehavior and also to charge fees randomly | ? | txCollateral | [CTransaction](#ctransaction) | Collateral transaction which is used to prevent misbehavior and also to charge fees randomly
| ? | vecTxDSOut | CTxDSOut[] | vector of user outputs (CTxDSOut serialization is equal to [CTxOut](#ctxout) serialization) | ? | vecTxOut | CTxOut[] | vector of user outputs
### DSSIGNFINALTX - "dss" ### DSSIGNFINALTX - "dss"

View File

@ -1,116 +0,0 @@
#include "darksend.h"
#include "darksend-relay.h"
#include "messagesigner.h"
CDarkSendRelay::CDarkSendRelay()
{
vinMasternode = CTxIn();
nBlockHeight = 0;
nRelayType = 0;
in = CTxIn();
out = CTxOut();
}
CDarkSendRelay::CDarkSendRelay(CTxIn& vinMasternodeIn, vector<unsigned char>& vchSigIn, int nBlockHeightIn, int nRelayTypeIn, CTxIn& in2, CTxOut& out2)
{
vinMasternode = vinMasternodeIn;
vchSig = vchSigIn;
nBlockHeight = nBlockHeightIn;
nRelayType = nRelayTypeIn;
in = in2;
out = out2;
}
std::string CDarkSendRelay::ToString()
{
std::ostringstream info;
info << "vin: " << vinMasternode.ToString() <<
" nBlockHeight: " << (int)nBlockHeight <<
" nRelayType: " << (int)nRelayType <<
" in " << in.ToString() <<
" out " << out.ToString();
return info.str();
}
bool CDarkSendRelay::Sign(std::string strSharedKey)
{
std::string strError = "";
std::string strMessage = in.ToString() + out.ToString();
CKey key2;
CPubKey pubkey2;
if(!CMessageSigner::GetKeysFromSecret(strSharedKey, key2, pubkey2)) {
LogPrintf("CDarkSendRelay::Sign -- GetKeysFromSecret() failed, invalid shared key %s\n", strSharedKey);
return false;
}
if(!CMessageSigner::SignMessage(strMessage, vchSig2, key2)) {
LogPrintf("CDarkSendRelay::Sign -- SignMessage() failed\n");
return false;
}
if(!CMessageSigner::VerifyMessage(pubkey2, vchSig2, strMessage, strError)) {
LogPrintf("CDarkSendRelay::Sign -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
return true;
}
bool CDarkSendRelay::VerifyMessage(std::string strSharedKey)
{
std::string strError = "";
std::string strMessage = in.ToString() + out.ToString();
CKey key2;
CPubKey pubkey2;
if(!CMessageSigner::GetKeysFromSecret(strSharedKey, key2, pubkey2)) {
LogPrintf("CDarkSendRelay::VerifyMessage -- GetKeysFromSecret() failed, invalid shared key %s\n", strSharedKey);
return false;
}
if(!CMessageSigner::VerifyMessage(pubkey2, vchSig2, strMessage, strError)) {
LogPrintf("CDarkSendRelay::VerifyMessage -- VerifyMessage() failed, error: %s\n", strError);
return false;
}
return true;
}
void CDarkSendRelay::Relay()
{
int nCount = std::min(mnodeman.CountEnabled(MIN_PRIVATESEND_PEER_PROTO_VERSION), 20);
int nRank1 = (rand() % nCount)+1;
int nRank2 = (rand() % nCount)+1;
//keep picking another second number till we get one that doesn't match
while(nRank1 == nRank2) nRank2 = (rand() % nCount)+1;
//printf("rank 1 - rank2 %d %d \n", nRank1, nRank2);
//relay this message through 2 separate nodes for redundancy
RelayThroughNode(nRank1);
RelayThroughNode(nRank2);
}
void CDarkSendRelay::RelayThroughNode(int nRank)
{
masternode_info_t mnInfo;
if(mnodeman.GetMasternodeByRank(nRank, mnInfo, nBlockHeight, MIN_PRIVATESEND_PEER_PROTO_VERSION)) {
//printf("RelayThroughNode %s\n", mnInfo.addr.ToString().c_str());
// TODO: Pass CConnman instance somehow and don't use global variable.
CNode* pnode = g_connman->ConnectNode((CAddress)mnInfo.addr, NULL);
if(pnode) {
//printf("Connected\n");
pnode->PushMessage("dsr", (*this));
return;
}
} else {
//printf("RelayThroughNode NULL\n");
}
}

View File

@ -1,51 +0,0 @@
// Copyright (c) 2014-2017 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef DARKSEND_RELAY_H
#define DARKSEND_RELAY_H
#include "validation.h"
#include "activemasternode.h"
#include "masternodeman.h"
class CDarkSendRelay
{
public:
CTxIn vinMasternode;
vector<unsigned char> vchSig;
vector<unsigned char> vchSig2;
int nBlockHeight;
int nRelayType;
CTxIn in;
CTxOut out;
CDarkSendRelay();
CDarkSendRelay(CTxIn& vinMasternodeIn, vector<unsigned char>& vchSigIn, int nBlockHeightIn, int nRelayTypeIn, CTxIn& in2, CTxOut& out2);
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(vinMasternode);
READWRITE(vchSig);
READWRITE(vchSig2);
READWRITE(nBlockHeight);
READWRITE(nRelayType);
READWRITE(in);
READWRITE(out);
}
std::string ToString();
bool Sign(std::string strSharedKey);
bool VerifyMessage(std::string strSharedKey);
void Relay();
void RelayThroughNode(int nRank);
};
#endif

View File

@ -693,51 +693,16 @@ bool CMasternodeMan::GetMasternodeRanks(CMasternodeMan::rank_pair_vec_t& vecMast
return true; return true;
} }
bool CMasternodeMan::GetMasternodeByRank(int nRankIn, masternode_info_t& mnInfoRet, int nBlockHeight, int nMinProtocol)
{
mnInfoRet = masternode_info_t();
if (!masternodeSync.IsMasternodeListSynced())
return false;
// make sure we know about this block
uint256 nBlockHash = uint256();
if (!GetBlockHash(nBlockHash, nBlockHeight)) {
LogPrintf("CMasternodeMan::%s -- ERROR: GetBlockHash() failed at nBlockHeight %d\n", __func__, nBlockHeight);
return false;
}
LOCK(cs);
score_pair_vec_t vecMasternodeScores;
if (!GetMasternodeScores(nBlockHash, vecMasternodeScores, nMinProtocol))
return false;
if (vecMasternodeScores.size() < nRankIn)
return false;
int nRank = 0;
for (auto& scorePair : vecMasternodeScores) {
nRank++;
if(nRank == nRankIn) {
mnInfoRet = *scorePair.second;
return true;
}
}
return false;
}
void CMasternodeMan::ProcessMasternodeConnections(CConnman& connman) void CMasternodeMan::ProcessMasternodeConnections(CConnman& connman)
{ {
//we don't care about this for regtest //we don't care about this for regtest
if(Params().NetworkIDString() == CBaseChainParams::REGTEST) return; if(Params().NetworkIDString() == CBaseChainParams::REGTEST) return;
connman.ForEachNode(CConnman::AllNodes, [](CNode* pnode) { connman.ForEachNode(CConnman::AllNodes, [](CNode* pnode) {
if(pnode->fMasternode) {
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
if(privateSendClient.infoMixingMasternode.fInfoValid && pnode->addr == privateSendClient.infoMixingMasternode.addr) if(pnode->fMasternode && !privateSendClient.IsMixingMasternode(pnode)) {
return; #else
if(pnode->fMasternode) {
#endif // ENABLE_WALLET #endif // ENABLE_WALLET
LogPrintf("Closing Masternode connection: peer=%d, addr=%s\n", pnode->id, pnode->addr.ToString()); LogPrintf("Closing Masternode connection: peer=%d, addr=%s\n", pnode->id, pnode->addr.ToString());
pnode->fDisconnect = true; pnode->fDisconnect = true;

View File

@ -177,7 +177,6 @@ public:
bool GetMasternodeRanks(rank_pair_vec_t& vecMasternodeRanksRet, int nBlockHeight = -1, int nMinProtocol = 0); bool GetMasternodeRanks(rank_pair_vec_t& vecMasternodeRanksRet, int nBlockHeight = -1, int nMinProtocol = 0);
bool GetMasternodeRank(const COutPoint &outpoint, int& nRankRet, int nBlockHeight = -1, int nMinProtocol = 0); bool GetMasternodeRank(const COutPoint &outpoint, int& nRankRet, int nBlockHeight = -1, int nMinProtocol = 0);
bool GetMasternodeByRank(int nRank, masternode_info_t& mnInfoRet, int nBlockHeight = -1, int nMinProtocol = 0);
void ProcessMasternodeConnections(CConnman& connman); void ProcessMasternodeConnections(CConnman& connman);
std::pair<CService, std::set<uint256> > PopScheduledMnbRequestConnection(); std::pair<CService, std::set<uint256> > PopScheduledMnbRequestConnection();

View File

@ -61,7 +61,6 @@ public:
COutPoint prevout; COutPoint prevout;
CScript scriptSig; CScript scriptSig;
uint32_t nSequence; uint32_t nSequence;
CScript prevPubKey;
/* Setting nSequence to this value for every input in a transaction /* Setting nSequence to this value for every input in a transaction
* disables nLockTime. */ * disables nLockTime. */

View File

@ -285,6 +285,17 @@ std::string CPrivateSendClient::GetStatus()
} }
} }
bool CPrivateSendClient::GetMixingMasternodeInfo(masternode_info_t& mnInfoRet)
{
mnInfoRet = infoMixingMasternode.fInfoValid ? infoMixingMasternode : masternode_info_t();
return infoMixingMasternode.fInfoValid;
}
bool CPrivateSendClient::IsMixingMasternode(const CNode* pnode)
{
return infoMixingMasternode.fInfoValid && pnode->addr == infoMixingMasternode.addr;
}
// //
// Check the mixing progress and send client updates if a Masternode // Check the mixing progress and send client updates if a Masternode
// //
@ -308,19 +319,7 @@ void CPrivateSendClient::CheckPool()
// //
void CPrivateSendClient::CheckTimeout() void CPrivateSendClient::CheckTimeout()
{ {
{ CheckQueue();
TRY_LOCK(cs_darksend, lockDS);
if(!lockDS) return; // it's ok to fail here, we run this quite frequently
// check mixing queue objects for timeouts
std::vector<CDarksendQueue>::iterator it = vecDarksendQueue.begin();
while(it != vecDarksendQueue.end()) {
if((*it).IsExpired()) {
LogPrint("privatesend", "CPrivateSendClient::CheckTimeout -- Removing expired queue (%s)\n", (*it).ToString());
it = vecDarksendQueue.erase(it);
} else ++it;
}
}
if(!fEnablePrivateSend && !fMasterNode) return; if(!fEnablePrivateSend && !fMasterNode) return;
@ -359,7 +358,7 @@ void CPrivateSendClient::CheckTimeout()
// Execute a mixing denomination via a Masternode. // Execute a mixing denomination via a Masternode.
// This is only ran from clients // This is only ran from clients
// //
bool CPrivateSendClient::SendDenominate(const std::vector<CTxIn>& vecTxIn, const std::vector<CTxOut>& vecTxOut, CConnman& connman) bool CPrivateSendClient::SendDenominate(const std::vector<CTxDSIn>& vecTxDSIn, const std::vector<CTxOut>& vecTxOut, CConnman& connman)
{ {
if(fMasterNode) { if(fMasterNode) {
LogPrintf("CPrivateSendClient::SendDenominate -- PrivateSend from a Masternode is not supported currently.\n"); LogPrintf("CPrivateSendClient::SendDenominate -- PrivateSend from a Masternode is not supported currently.\n");
@ -375,8 +374,8 @@ bool CPrivateSendClient::SendDenominate(const std::vector<CTxIn>& vecTxIn, const
BOOST_FOREACH(CTxIn txin, txMyCollateral.vin) BOOST_FOREACH(CTxIn txin, txMyCollateral.vin)
vecOutPointLocked.push_back(txin.prevout); vecOutPointLocked.push_back(txin.prevout);
BOOST_FOREACH(CTxIn txin, vecTxIn) for (const auto& txdsin : vecTxDSIn)
vecOutPointLocked.push_back(txin.prevout); vecOutPointLocked.push_back(txdsin.prevout);
// we should already be connected to a Masternode // we should already be connected to a Masternode
if(!nSessionID) { if(!nSessionID) {
@ -406,9 +405,9 @@ bool CPrivateSendClient::SendDenominate(const std::vector<CTxIn>& vecTxIn, const
CValidationState validationState; CValidationState validationState;
CMutableTransaction tx; CMutableTransaction tx;
BOOST_FOREACH(const CTxIn& txin, vecTxIn) { for (const auto& txdsin : vecTxDSIn) {
LogPrint("privatesend", "CPrivateSendClient::SendDenominate -- txin=%s\n", txin.ToString()); LogPrint("privatesend", "CPrivateSendClient::SendDenominate -- txdsin=%s\n", txdsin.ToString());
tx.vin.push_back(txin); tx.vin.push_back(txdsin);
} }
BOOST_FOREACH(const CTxOut& txout, vecTxOut) { BOOST_FOREACH(const CTxOut& txout, vecTxOut) {
@ -430,7 +429,7 @@ bool CPrivateSendClient::SendDenominate(const std::vector<CTxIn>& vecTxIn, const
} }
// store our entry for later use // store our entry for later use
CDarkSendEntry entry(vecTxIn, vecTxOut, txMyCollateral); CDarkSendEntry entry(vecTxDSIn, vecTxOut, txMyCollateral);
vecEntries.push_back(entry); vecEntries.push_back(entry);
RelayIn(entry, connman); RelayIn(entry, connman);
nTimeLastSuccessfulStep = GetTimeMillis(); nTimeLastSuccessfulStep = GetTimeMillis();
@ -527,19 +526,19 @@ bool CPrivateSendClient::SignFinalTransaction(const CTransaction& finalTransacti
CAmount nValue1 = 0; CAmount nValue1 = 0;
CAmount nValue2 = 0; CAmount nValue2 = 0;
for(unsigned int i = 0; i < finalMutableTransaction.vout.size(); i++) { for (const auto& txoutFinal : finalMutableTransaction.vout) {
BOOST_FOREACH(const CTxOut& txout, entry.vecTxDSOut) { for (const auto& txout: entry.vecTxOut) {
if(finalMutableTransaction.vout[i] == txout) { if(txoutFinal == txout) {
nFoundOutputsCount++; nFoundOutputsCount++;
nValue1 += finalMutableTransaction.vout[i].nValue; nValue1 += txoutFinal.nValue;
} }
} }
} }
BOOST_FOREACH(const CTxOut txout, entry.vecTxDSOut) for (const auto& txout : entry.vecTxOut)
nValue2 += txout.nValue; nValue2 += txout.nValue;
int nTargetOuputsCount = entry.vecTxDSOut.size(); int nTargetOuputsCount = entry.vecTxOut.size();
if(nFoundOutputsCount < nTargetOuputsCount || nValue1 != nValue2) { if(nFoundOutputsCount < nTargetOuputsCount || nValue1 != nValue2) {
// in this case, something went wrong and we'll refuse to sign. It's possible we'll be charged collateral. But that's // in this case, something went wrong and we'll refuse to sign. It's possible we'll be charged collateral. But that's
// better then signing if the transaction doesn't look like what we wanted. // better then signing if the transaction doesn't look like what we wanted.
@ -583,18 +582,6 @@ bool CPrivateSendClient::SignFinalTransaction(const CTransaction& finalTransacti
return true; return true;
} }
void CPrivateSendClient::NewBlock()
{
static int64_t nTimeNewBlockReceived = 0;
//we we're processing lots of blocks, we'll just leave
if(GetTime() - nTimeNewBlockReceived < 10) return;
nTimeNewBlockReceived = GetTime();
LogPrint("privatesend", "CPrivateSendClient::NewBlock\n");
CheckTimeout();
}
// mixing transaction was completed (failed or successful) // mixing transaction was completed (failed or successful)
void CPrivateSendClient::CompletedTransaction(PoolMessage nMessageID) void CPrivateSendClient::CompletedTransaction(PoolMessage nMessageID)
{ {
@ -875,11 +862,11 @@ bool CPrivateSendClient::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CCon
LogPrint("privatesend", "CPrivateSendClient::JoinExistingQueue -- found valid queue: %s\n", dsq.ToString()); LogPrint("privatesend", "CPrivateSendClient::JoinExistingQueue -- found valid queue: %s\n", dsq.ToString());
CAmount nValueInTmp = 0; CAmount nValueInTmp = 0;
std::vector<CTxIn> vecTxInTmp; std::vector<CTxDSIn> vecTxDSInTmp;
std::vector<COutput> vCoinsTmp; std::vector<COutput> vCoinsTmp;
// Try to match their denominations if possible, select at least 1 denominations // Try to match their denominations if possible, select at least 1 denominations
if(!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, vecStandardDenoms[vecBits.front()], nBalanceNeedsAnonymized, vecTxInTmp, vCoinsTmp, nValueInTmp, 0, nPrivateSendRounds)) { if(!pwalletMain->SelectCoinsByDenominations(dsq.nDenom, vecStandardDenoms[vecBits.front()], nBalanceNeedsAnonymized, vecTxDSInTmp, vCoinsTmp, nValueInTmp, 0, nPrivateSendRounds)) {
LogPrintf("CPrivateSendClient::JoinExistingQueue -- Couldn't match denominations %d %d (%s)\n", vecBits.front(), dsq.nDenom, CPrivateSend::GetDenominationsToString(dsq.nDenom)); LogPrintf("CPrivateSendClient::JoinExistingQueue -- Couldn't match denominations %d %d (%s)\n", vecBits.front(), dsq.nDenom, CPrivateSend::GetDenominationsToString(dsq.nDenom));
continue; continue;
} }
@ -1011,23 +998,23 @@ bool CPrivateSendClient::StartNewQueue(CAmount nValueMin, CAmount nBalanceNeedsA
bool CPrivateSendClient::SubmitDenominate(CConnman& connman) bool CPrivateSendClient::SubmitDenominate(CConnman& connman)
{ {
std::string strError; std::string strError;
std::vector<CTxIn> vecTxInRet; std::vector<CTxDSIn> vecTxDSInRet;
std::vector<CTxOut> vecTxOutRet; std::vector<CTxOut> vecTxOutRet;
// Submit transaction to the pool if we get here // Submit transaction to the pool if we get here
// Try to use only inputs with the same number of rounds starting from the highest number of rounds possible // Try to use only inputs with the same number of rounds starting from the highest number of rounds possible
for(int i = nPrivateSendRounds; i > 0; i--) { for(int i = nPrivateSendRounds; i > 0; i--) {
if(PrepareDenominate(i - 1, i, strError, vecTxInRet, vecTxOutRet)) { if(PrepareDenominate(i - 1, i, strError, vecTxDSInRet, vecTxOutRet)) {
LogPrintf("CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i); LogPrintf("CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
return SendDenominate(vecTxInRet, vecTxOutRet, connman); return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
} }
LogPrint("privatesend", "CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError); LogPrint("privatesend", "CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
} }
// We failed? That's strange but let's just make final attempt and try to mix everything // We failed? That's strange but let's just make final attempt and try to mix everything
if(PrepareDenominate(0, nPrivateSendRounds, strError, vecTxInRet, vecTxOutRet)) { if(PrepareDenominate(0, nPrivateSendRounds, strError, vecTxDSInRet, vecTxOutRet)) {
LogPrintf("CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for all rounds, success\n"); LogPrintf("CPrivateSendClient::SubmitDenominate -- Running PrivateSend denominate for all rounds, success\n");
return SendDenominate(vecTxInRet, vecTxOutRet, connman); return SendDenominate(vecTxDSInRet, vecTxOutRet, connman);
} }
// Should never actually get here but just in case // Should never actually get here but just in case
@ -1036,7 +1023,7 @@ bool CPrivateSendClient::SubmitDenominate(CConnman& connman)
return false; return false;
} }
bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, std::vector<CTxIn>& vecTxInRet, std::vector<CTxOut>& vecTxOutRet) bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, std::vector<CTxDSIn>& vecTxDSInRet, std::vector<CTxOut>& vecTxOutRet)
{ {
if(!pwalletMain) { if(!pwalletMain) {
strErrorRet = "Wallet is not initialized"; strErrorRet = "Wallet is not initialized";
@ -1054,11 +1041,11 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std::
} }
// make sure returning vectors are empty before filling them up // make sure returning vectors are empty before filling them up
vecTxInRet.clear(); vecTxDSInRet.clear();
vecTxOutRet.clear(); vecTxOutRet.clear();
// ** find the coins we'll use // ** find the coins we'll use
std::vector<CTxIn> vecTxIn; std::vector<CTxDSIn> vecTxDSIn;
std::vector<COutput> vCoins; std::vector<COutput> vCoins;
CAmount nValueIn = 0; CAmount nValueIn = 0;
@ -1073,7 +1060,7 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std::
return false; return false;
} }
std::vector<CAmount> vecStandardDenoms = CPrivateSend::GetStandardDenominations(); std::vector<CAmount> vecStandardDenoms = CPrivateSend::GetStandardDenominations();
bool fSelected = pwalletMain->SelectCoinsByDenominations(nSessionDenom, vecStandardDenoms[vecBits.front()], CPrivateSend::GetMaxPoolAmount(), vecTxIn, vCoins, nValueIn, nMinRounds, nMaxRounds); bool fSelected = pwalletMain->SelectCoinsByDenominations(nSessionDenom, vecStandardDenoms[vecBits.front()], CPrivateSend::GetMaxPoolAmount(), vecTxDSIn, vCoins, nValueIn, nMinRounds, nMaxRounds);
if (nMinRounds >= 0 && !fSelected) { if (nMinRounds >= 0 && !fSelected) {
strErrorRet = "Can't select current denominated inputs"; strErrorRet = "Can't select current denominated inputs";
return false; return false;
@ -1083,7 +1070,7 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std::
{ {
LOCK(pwalletMain->cs_wallet); LOCK(pwalletMain->cs_wallet);
BOOST_FOREACH(CTxIn txin, vecTxIn) { for (auto& txin : vecTxDSIn) {
pwalletMain->LockCoin(txin.prevout); pwalletMain->LockCoin(txin.prevout);
} }
} }
@ -1102,15 +1089,15 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std::
if (nValueLeft - nValueDenom < 0) continue; if (nValueLeft - nValueDenom < 0) continue;
// Note: this relies on a fact that both vectors MUST have same size // Note: this relies on a fact that both vectors MUST have same size
std::vector<CTxIn>::iterator it = vecTxIn.begin(); std::vector<CTxDSIn>::iterator it = vecTxDSIn.begin();
std::vector<COutput>::iterator it2 = vCoins.begin(); std::vector<COutput>::iterator it2 = vCoins.begin();
while (it2 != vCoins.end()) { while (it2 != vCoins.end()) {
// we have matching inputs // we have matching inputs
if ((*it2).tx->vout[(*it2).i].nValue == nValueDenom) { if ((*it2).tx->vout[(*it2).i].nValue == nValueDenom) {
// add new input in resulting vector // add new input in resulting vector
vecTxInRet.push_back(*it); vecTxDSInRet.push_back(*it);
// remove corresponting items from initial vectors // remove corresponting items from initial vectors
vecTxIn.erase(it); vecTxDSIn.erase(it);
vCoins.erase(it2); vCoins.erase(it2);
CScript scriptDenom = keyHolderStorage.AddKey(pwalletMain).GetScriptForDestination(); CScript scriptDenom = keyHolderStorage.AddKey(pwalletMain).GetScriptForDestination();
@ -1136,7 +1123,7 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std::
{ {
// unlock unused coins // unlock unused coins
LOCK(pwalletMain->cs_wallet); LOCK(pwalletMain->cs_wallet);
BOOST_FOREACH(CTxIn txin, vecTxIn) { for (auto& txin : vecTxDSIn) {
pwalletMain->UnlockCoin(txin.prevout); pwalletMain->UnlockCoin(txin.prevout);
} }
} }
@ -1144,7 +1131,7 @@ bool CPrivateSendClient::PrepareDenominate(int nMinRounds, int nMaxRounds, std::
if (CPrivateSend::GetDenominations(vecTxOutRet) != nSessionDenom) { if (CPrivateSend::GetDenominations(vecTxOutRet) != nSessionDenom) {
// unlock used coins on failure // unlock used coins on failure
LOCK(pwalletMain->cs_wallet); LOCK(pwalletMain->cs_wallet);
BOOST_FOREACH(CTxIn txin, vecTxInRet) { for (auto& txin : vecTxDSInRet) {
pwalletMain->UnlockCoin(txin.prevout); pwalletMain->UnlockCoin(txin.prevout);
} }
keyHolderStorage.ReturnAll(); keyHolderStorage.ReturnAll();
@ -1188,7 +1175,7 @@ bool CPrivateSendClient::MakeCollateralAmounts(const CompactTallyItem& tallyItem
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
// denominated input is always a single one, so we can check its amount directly and return early // denominated input is always a single one, so we can check its amount directly and return early
if(!fTryDenominated && tallyItem.vecTxIn.size() == 1 && pwalletMain->IsDenominatedAmount(tallyItem.nAmount)) if(!fTryDenominated && tallyItem.vecTxIn.size() == 1 && CPrivateSend::IsDenominatedAmount(tallyItem.nAmount))
return false; return false;
CWalletTx wtx; CWalletTx wtx;
@ -1404,10 +1391,6 @@ void CPrivateSendClient::UpdatedBlockTip(const CBlockIndex *pindex)
nCachedBlockHeight = pindex->nHeight; nCachedBlockHeight = pindex->nHeight;
LogPrint("privatesend", "CPrivateSendClient::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight); LogPrint("privatesend", "CPrivateSendClient::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight);
if(!fLiteMode && masternodeSync.IsMasternodeListSynced()) {
NewBlock();
}
CPrivateSend::CheckDSTXes(pindex->nHeight); CPrivateSend::CheckDSTXes(pindex->nHeight);
} }

View File

@ -34,8 +34,6 @@ extern CPrivateSendClient privateSendClient;
class CPrivateSendClient : public CPrivateSendBase class CPrivateSendClient : public CPrivateSendBase
{ {
private: private:
mutable CCriticalSection cs_darksend;
// Keep track of the used Masternodes // Keep track of the used Masternodes
std::vector<COutPoint> vecMasternodesUsed; std::vector<COutPoint> vecMasternodesUsed;
@ -54,6 +52,7 @@ private:
std::string strLastMessage; std::string strLastMessage;
std::string strAutoDenomResult; std::string strAutoDenomResult;
masternode_info_t infoMixingMasternode;
CMutableTransaction txMyCollateral; // client side collateral CMutableTransaction txMyCollateral; // client side collateral
CKeyHolderStorage keyHolderStorage; // storage for keys used in PrepareDenominate CKeyHolderStorage keyHolderStorage; // storage for keys used in PrepareDenominate
@ -84,9 +83,9 @@ private:
/// As a client, submit part of a future mixing transaction to a Masternode to start the process /// As a client, submit part of a future mixing transaction to a Masternode to start the process
bool SubmitDenominate(CConnman& connman); bool SubmitDenominate(CConnman& connman);
/// step 1: prepare denominated inputs and outputs /// step 1: prepare denominated inputs and outputs
bool PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, std::vector<CTxIn>& vecTxInRet, std::vector<CTxOut>& vecTxOutRet); bool PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, std::vector<CTxDSIn>& vecTxDSInRet, std::vector<CTxOut>& vecTxOutRet);
/// step 2: send denominated inputs and outputs prepared in step 1 /// step 2: send denominated inputs and outputs prepared in step 1
bool SendDenominate(const std::vector<CTxIn>& vecTxIn, const std::vector<CTxOut>& vecTxOut, CConnman& connman); bool SendDenominate(const std::vector<CTxDSIn>& vecTxDSIn, const std::vector<CTxOut>& vecTxOut, CConnman& connman);
/// Get Masternode updates about the progress of mixing /// Get Masternode updates about the progress of mixing
bool CheckPoolStateUpdate(PoolState nStateNew, int nEntriesCountNew, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, int nSessionIDNew=0); bool CheckPoolStateUpdate(PoolState nStateNew, int nEntriesCountNew, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, int nSessionIDNew=0);
@ -107,7 +106,6 @@ public:
bool fEnablePrivateSend; bool fEnablePrivateSend;
bool fPrivateSendMultiSession; bool fPrivateSendMultiSession;
masternode_info_t infoMixingMasternode;
int nCachedNumBlocks; //used for the overview screen int nCachedNumBlocks; //used for the overview screen
bool fCreateAutoBackups; //builtin support for automatic backups bool fCreateAutoBackups; //builtin support for automatic backups
@ -129,20 +127,21 @@ public:
void SetMinBlocksToWait(int nMinBlocksToWaitIn) { nMinBlocksToWait = nMinBlocksToWaitIn; } void SetMinBlocksToWait(int nMinBlocksToWaitIn) { nMinBlocksToWait = nMinBlocksToWaitIn; }
void ResetPool(); void ResetPool();
void UnlockCoins(); void UnlockCoins();
std::string GetStatus(); std::string GetStatus();
bool GetMixingMasternodeInfo(masternode_info_t& mnInfoRet);
bool IsMixingMasternode(const CNode* pnode);
/// Passively run mixing in the background according to the configuration in settings /// Passively run mixing in the background according to the configuration in settings
bool DoAutomaticDenominating(CConnman& connman, bool fDryRun=false); bool DoAutomaticDenominating(CConnman& connman, bool fDryRun=false);
void CheckTimeout(); void CheckTimeout();
/// Process a new block
void NewBlock();
void UpdatedBlockTip(const CBlockIndex *pindex); void UpdatedBlockTip(const CBlockIndex *pindex);
}; };

View File

@ -153,14 +153,14 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C
return; return;
} }
if(entry.vecTxDSOut.size() > PRIVATESEND_ENTRY_MAX_SIZE) { if(entry.vecTxOut.size() > PRIVATESEND_ENTRY_MAX_SIZE) {
LogPrintf("DSVIN -- ERROR: too many outputs! %d/%d\n", entry.vecTxDSOut.size(), PRIVATESEND_ENTRY_MAX_SIZE); LogPrintf("DSVIN -- ERROR: too many outputs! %d/%d\n", entry.vecTxOut.size(), PRIVATESEND_ENTRY_MAX_SIZE);
PushStatus(pfrom, STATUS_REJECTED, ERR_MAXIMUM, connman); PushStatus(pfrom, STATUS_REJECTED, ERR_MAXIMUM, connman);
return; return;
} }
//do we have the same denominations as the current session? //do we have the same denominations as the current session?
if(!IsOutputsCompatibleWithSessionDenom(entry.vecTxDSOut)) { if(!IsOutputsCompatibleWithSessionDenom(entry.vecTxOut)) {
LogPrintf("DSVIN -- not compatible with existing transactions!\n"); LogPrintf("DSVIN -- not compatible with existing transactions!\n");
PushStatus(pfrom, STATUS_REJECTED, ERR_EXISTING_TX, connman); PushStatus(pfrom, STATUS_REJECTED, ERR_EXISTING_TX, connman);
return; return;
@ -173,7 +173,7 @@ void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, C
CMutableTransaction tx; CMutableTransaction tx;
BOOST_FOREACH(const CTxOut txout, entry.vecTxDSOut) { for (const auto& txout : entry.vecTxOut) {
nValueOut += txout.nValue; nValueOut += txout.nValue;
tx.vout.push_back(txout); tx.vout.push_back(txout);
@ -311,8 +311,8 @@ void CPrivateSendServer::CreateFinalTransaction(CConnman& connman)
// make our new transaction // make our new transaction
for(int i = 0; i < GetEntriesCount(); i++) { for(int i = 0; i < GetEntriesCount(); i++) {
BOOST_FOREACH(const CTxDSOut& txdsout, vecEntries[i].vecTxDSOut) for (const auto& txout : vecEntries[i].vecTxOut)
txNew.vout.push_back(txdsout); txNew.vout.push_back(txout);
BOOST_FOREACH(const CTxDSIn& txdsin, vecEntries[i].vecTxDSIn) BOOST_FOREACH(const CTxDSIn& txdsin, vecEntries[i].vecTxDSIn)
txNew.vin.push_back(txdsin); txNew.vin.push_back(txdsin);
@ -495,19 +495,7 @@ void CPrivateSendServer::ChargeRandomFees(CConnman& connman)
// //
void CPrivateSendServer::CheckTimeout(CConnman& connman) void CPrivateSendServer::CheckTimeout(CConnman& connman)
{ {
{ CheckQueue();
TRY_LOCK(cs_darksend, lockDS);
if(!lockDS) return; // it's ok to fail here, we run this quite frequently
// check mixing queue objects for timeouts
std::vector<CDarksendQueue>::iterator it = vecDarksendQueue.begin();
while(it != vecDarksendQueue.end()) {
if((*it).IsExpired()) {
LogPrint("privatesend", "CPrivateSendServer::CheckTimeout -- Removing expired queue (%s)\n", (*it).ToString());
it = vecDarksendQueue.erase(it);
} else ++it;
}
}
if(!fMasterNode) return; if(!fMasterNode) return;
@ -556,8 +544,8 @@ bool CPrivateSendServer::IsInputScriptSigValid(const CTxIn& txin)
BOOST_FOREACH(CDarkSendEntry& entry, vecEntries) { BOOST_FOREACH(CDarkSendEntry& entry, vecEntries) {
BOOST_FOREACH(const CTxDSOut& txdsout, entry.vecTxDSOut) for (const auto& txout : entry.vecTxOut)
txNew.vout.push_back(txdsout); txNew.vout.push_back(txout);
BOOST_FOREACH(const CTxDSIn& txdsin, entry.vecTxDSIn) { BOOST_FOREACH(const CTxDSIn& txdsin, entry.vecTxDSIn) {
txNew.vin.push_back(txdsin); txNew.vin.push_back(txdsin);
@ -658,7 +646,6 @@ bool CPrivateSendServer::AddScriptSig(const CTxIn& txinNew)
BOOST_FOREACH(CTxIn& txin, finalMutableTransaction.vin) { BOOST_FOREACH(CTxIn& txin, finalMutableTransaction.vin) {
if(txinNew.prevout == txin.prevout && txin.nSequence == txinNew.nSequence) { if(txinNew.prevout == txin.prevout && txin.nSequence == txinNew.nSequence) {
txin.scriptSig = txinNew.scriptSig; txin.scriptSig = txinNew.scriptSig;
txin.prevPubKey = txinNew.prevPubKey;
LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- adding to finalMutableTransaction, scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0,24)); LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- adding to finalMutableTransaction, scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0,24));
} }
} }
@ -683,14 +670,14 @@ bool CPrivateSendServer::IsSignaturesComplete()
return true; return true;
} }
bool CPrivateSendServer::IsOutputsCompatibleWithSessionDenom(const std::vector<CTxDSOut>& vecTxDSOut) bool CPrivateSendServer::IsOutputsCompatibleWithSessionDenom(const std::vector<CTxOut>& vecTxOut)
{ {
if(CPrivateSend::GetDenominations(vecTxDSOut) == 0) return false; if(CPrivateSend::GetDenominations(vecTxOut) == 0) return false;
BOOST_FOREACH(const CDarkSendEntry entry, vecEntries) { BOOST_FOREACH(const CDarkSendEntry entry, vecEntries) {
LogPrintf("CPrivateSendServer::IsOutputsCompatibleWithSessionDenom -- vecTxDSOut denom %d, entry.vecTxDSOut denom %d\n", LogPrintf("CPrivateSendServer::IsOutputsCompatibleWithSessionDenom -- vecTxOut denom %d, entry.vecTxOut denom %d\n",
CPrivateSend::GetDenominations(vecTxDSOut), CPrivateSend::GetDenominations(entry.vecTxDSOut)); CPrivateSend::GetDenominations(vecTxOut), CPrivateSend::GetDenominations(entry.vecTxOut));
if(CPrivateSend::GetDenominations(vecTxDSOut) != CPrivateSend::GetDenominations(entry.vecTxDSOut)) return false; if(CPrivateSend::GetDenominations(vecTxOut) != CPrivateSend::GetDenominations(entry.vecTxOut)) return false;
} }
return true; return true;

View File

@ -18,8 +18,6 @@ extern CPrivateSendServer privateSendServer;
class CPrivateSendServer : public CPrivateSendBase class CPrivateSendServer : public CPrivateSendBase
{ {
private: private:
mutable CCriticalSection cs_darksend;
// Mixing uses collateral transactions to trust parties entering the pool // Mixing uses collateral transactions to trust parties entering the pool
// to behave honestly. If they don't it takes their money. // to behave honestly. If they don't it takes their money.
std::vector<CTransaction> vecSessionCollaterals; std::vector<CTransaction> vecSessionCollaterals;
@ -54,7 +52,7 @@ private:
/// Check to make sure a given input matches an input in the pool and its scriptSig is valid /// Check to make sure a given input matches an input in the pool and its scriptSig is valid
bool IsInputScriptSigValid(const CTxIn& txin); bool IsInputScriptSigValid(const CTxIn& txin);
/// Are these outputs compatible with other client in the pool? /// Are these outputs compatible with other client in the pool?
bool IsOutputsCompatibleWithSessionDenom(const std::vector<CTxDSOut>& vecTxDSOut); bool IsOutputsCompatibleWithSessionDenom(const std::vector<CTxOut>& vecTxOut);
// Set the 'state' value, with some logging and capturing when the state changed // Set the 'state' value, with some logging and capturing when the state changed
void SetState(PoolState nStateNew); void SetState(PoolState nStateNew);

View File

@ -19,15 +19,6 @@
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
CDarkSendEntry::CDarkSendEntry(const std::vector<CTxIn>& vecTxIn, const std::vector<CTxOut>& vecTxOut, const CTransaction& txCollateral) :
txCollateral(txCollateral), addr(CService())
{
BOOST_FOREACH(CTxIn txin, vecTxIn)
vecTxDSIn.push_back(txin);
BOOST_FOREACH(CTxOut txout, vecTxOut)
vecTxDSOut.push_back(txout);
}
bool CDarkSendEntry::AddScriptSig(const CTxIn& txin) bool CDarkSendEntry::AddScriptSig(const CTxIn& txin)
{ {
BOOST_FOREACH(CTxDSIn& txdsin, vecTxDSIn) { BOOST_FOREACH(CTxDSIn& txdsin, vecTxDSIn) {
@ -35,7 +26,6 @@ bool CDarkSendEntry::AddScriptSig(const CTxIn& txin)
if(txdsin.fHasSig) return false; if(txdsin.fHasSig) return false;
txdsin.scriptSig = txin.scriptSig; txdsin.scriptSig = txin.scriptSig;
txdsin.prevPubKey = txin.prevPubKey;
txdsin.fHasSig = true; txdsin.fHasSig = true;
return true; return true;
@ -128,6 +118,21 @@ void CPrivateSendBase::SetNull()
nTimeLastSuccessfulStep = GetTimeMillis(); nTimeLastSuccessfulStep = GetTimeMillis();
} }
void CPrivateSendBase::CheckQueue()
{
TRY_LOCK(cs_darksend, lockDS);
if(!lockDS) return; // it's ok to fail here, we run this quite frequently
// check mixing queue objects for timeouts
std::vector<CDarksendQueue>::iterator it = vecDarksendQueue.begin();
while(it != vecDarksendQueue.end()) {
if((*it).IsExpired()) {
LogPrint("privatesend", "CPrivateSendBase::%s -- Removing expired queue (%s)\n", __func__, (*it).ToString());
it = vecDarksendQueue.erase(it);
} else ++it;
}
}
std::string CPrivateSendBase::GetStateString() const std::string CPrivateSendBase::GetStateString() const
{ {
switch(nState) { switch(nState) {
@ -217,6 +222,14 @@ bool CPrivateSend::IsCollateralValid(const CTransaction& txCollateral)
return true; return true;
} }
bool CPrivateSend::IsCollateralAmount(CAmount nInputAmount)
{
// collateral inputs should always be a 2x..4x of mixing collateral
return nInputAmount > GetCollateralAmount() &&
nInputAmount <= GetMaxCollateralAmount() &&
nInputAmount % GetCollateralAmount() == 0;
}
/* Create a nice string to show the denominations /* Create a nice string to show the denominations
Function returns as follows (for 4 denominations): Function returns as follows (for 4 denominations):
( bit on if present ) ( bit on if present )
@ -249,16 +262,6 @@ std::string CPrivateSend::GetDenominationsToString(int nDenom)
return strDenom; return strDenom;
} }
int CPrivateSend::GetDenominations(const std::vector<CTxDSOut>& vecTxDSOut)
{
std::vector<CTxOut> vecTxOut;
BOOST_FOREACH(CTxDSOut out, vecTxDSOut)
vecTxOut.push_back(out);
return GetDenominations(vecTxOut);
}
/* Return a bitshifted integer representing the denominations in this list /* Return a bitshifted integer representing the denominations in this list
Function returns as follows (for 4 denominations): Function returns as follows (for 4 denominations):
( bit on if present ) ( bit on if present )
@ -336,6 +339,14 @@ int CPrivateSend::GetDenominationsByAmounts(const std::vector<CAmount>& vecAmoun
return GetDenominations(vecTxOut, true); return GetDenominations(vecTxOut, true);
} }
bool CPrivateSend::IsDenominatedAmount(CAmount nInputAmount)
{
for (const auto& nDenomValue : vecStandardDenominations)
if(nInputAmount == nDenomValue)
return true;
return false;
}
std::string CPrivateSend::GetMessageByID(PoolMessage nMessageID) std::string CPrivateSend::GetMessageByID(PoolMessage nMessageID)
{ {
switch (nMessageID) { switch (nMessageID) {

View File

@ -77,58 +77,49 @@ enum PoolStatusUpdate {
class CTxDSIn : public CTxIn class CTxDSIn : public CTxIn
{ {
public: public:
// memory only
CScript prevPubKey;
bool fHasSig; // flag to indicate if signed bool fHasSig; // flag to indicate if signed
int nSentTimes; //times we've sent this anonymously int nSentTimes; //times we've sent this anonymously
CTxDSIn(const CTxIn& txin) : CTxDSIn(const CTxIn& txin, const CScript& script) :
CTxIn(txin), CTxIn(txin),
prevPubKey(script),
fHasSig(false), fHasSig(false),
nSentTimes(0) nSentTimes(0)
{} {}
CTxDSIn() : CTxDSIn() :
CTxIn(), CTxIn(),
prevPubKey(),
fHasSig(false), fHasSig(false),
nSentTimes(0) nSentTimes(0)
{} {}
}; };
/** Holds an mixing output
*/
class CTxDSOut : public CTxOut
{
public:
int nSentTimes; //times we've sent this anonymously
CTxDSOut(const CTxOut& out) :
CTxOut(out),
nSentTimes(0)
{}
CTxDSOut() :
CTxOut(),
nSentTimes(0)
{}
};
// A clients transaction in the mixing pool // A clients transaction in the mixing pool
class CDarkSendEntry class CDarkSendEntry
{ {
public: public:
std::vector<CTxDSIn> vecTxDSIn; std::vector<CTxDSIn> vecTxDSIn;
std::vector<CTxDSOut> vecTxDSOut; std::vector<CTxOut> vecTxOut;
CTransaction txCollateral; CTransaction txCollateral;
// memory only // memory only
CService addr; CService addr;
CDarkSendEntry() : CDarkSendEntry() :
vecTxDSIn(std::vector<CTxDSIn>()), vecTxDSIn(std::vector<CTxDSIn>()),
vecTxDSOut(std::vector<CTxDSOut>()), vecTxOut(std::vector<CTxOut>()),
txCollateral(CTransaction()), txCollateral(CTransaction()),
addr(CService()) addr(CService())
{} {}
CDarkSendEntry(const std::vector<CTxIn>& vecTxIn, const std::vector<CTxOut>& vecTxOut, const CTransaction& txCollateral); CDarkSendEntry(const std::vector<CTxDSIn>& vecTxDSIn, const std::vector<CTxOut>& vecTxOut, const CTransaction& txCollateral) :
vecTxDSIn(vecTxDSIn),
vecTxOut(vecTxOut),
txCollateral(txCollateral),
addr(CService())
{}
ADD_SERIALIZE_METHODS; ADD_SERIALIZE_METHODS;
@ -136,7 +127,7 @@ public:
inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) { inline void SerializationOp(Stream& s, Operation ser_action, int nType, int nVersion) {
READWRITE(vecTxDSIn); READWRITE(vecTxDSIn);
READWRITE(txCollateral); READWRITE(txCollateral);
READWRITE(vecTxDSOut); READWRITE(vecTxOut);
} }
bool AddScriptSig(const CTxIn& txin); bool AddScriptSig(const CTxIn& txin);
@ -279,6 +270,8 @@ public:
class CPrivateSendBase class CPrivateSendBase
{ {
protected: protected:
mutable CCriticalSection cs_darksend;
// The current mixing sessions in progress on the network // The current mixing sessions in progress on the network
std::vector<CDarksendQueue> vecDarksendQueue; std::vector<CDarksendQueue> vecDarksendQueue;
@ -292,6 +285,7 @@ protected:
CMutableTransaction finalMutableTransaction; // the finalized transaction ready for signing CMutableTransaction finalMutableTransaction; // the finalized transaction ready for signing
void SetNull(); void SetNull();
void CheckQueue();
public: public:
int nSessionDenom; //Users must submit an denom matching this int nSessionDenom; //Users must submit an denom matching this
@ -331,9 +325,10 @@ public:
/// Get the denominations for a specific amount of dash. /// Get the denominations for a specific amount of dash.
static int GetDenominationsByAmounts(const std::vector<CAmount>& vecAmount); static int GetDenominationsByAmounts(const std::vector<CAmount>& vecAmount);
static bool IsDenominatedAmount(CAmount nInputAmount);
/// Get the denominations for a list of outputs (returns a bitshifted integer) /// Get the denominations for a list of outputs (returns a bitshifted integer)
static int GetDenominations(const std::vector<CTxOut>& vecTxOut, bool fSingleRandomDenom = false); static int GetDenominations(const std::vector<CTxOut>& vecTxOut, bool fSingleRandomDenom = false);
static int GetDenominations(const std::vector<CTxDSOut>& vecTxDSOut);
static std::string GetDenominationsToString(int nDenom); static std::string GetDenominationsToString(int nDenom);
static bool GetDenominationsBits(int nDenom, std::vector<int> &vecBitsRet); static bool GetDenominationsBits(int nDenom, std::vector<int> &vecBitsRet);
@ -349,6 +344,8 @@ public:
static CAmount GetCollateralAmount() { return COLLATERAL; } static CAmount GetCollateralAmount() { return COLLATERAL; }
static CAmount GetMaxCollateralAmount() { return COLLATERAL*4; } static CAmount GetMaxCollateralAmount() { return COLLATERAL*4; }
static bool IsCollateralAmount(CAmount nInputAmount);
static void AddDSTX(const CDarksendBroadcastTx& dstx); static void AddDSTX(const CDarksendBroadcastTx& dstx);
static CDarksendBroadcastTx GetDSTX(const uint256& hash); static CDarksendBroadcastTx GetDSTX(const uint256& hash);
static void CheckDSTXes(int nHeight); static void CheckDSTXes(int nHeight);

View File

@ -105,7 +105,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
int nToMe = 0; int nToMe = 0;
BOOST_FOREACH(const CTxOut& txout, wtx.vout) { BOOST_FOREACH(const CTxOut& txout, wtx.vout) {
if(wallet->IsMine(txout)) { if(wallet->IsMine(txout)) {
fAllToMeDenom = fAllToMeDenom && wallet->IsDenominatedAmount(txout.nValue); fAllToMeDenom = fAllToMeDenom && CPrivateSend::IsDenominatedAmount(txout.nValue);
nToMe++; nToMe++;
} }
isminetype mine = wallet->IsMine(txout); isminetype mine = wallet->IsMine(txout);
@ -150,8 +150,8 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
const CTxOut& txout = wtx.vout[nOut]; const CTxOut& txout = wtx.vout[nOut];
sub.idx = parts.size(); sub.idx = parts.size();
if(wallet->IsCollateralAmount(txout.nValue)) sub.type = TransactionRecord::PrivateSendMakeCollaterals; if(CPrivateSend::IsCollateralAmount(txout.nValue)) sub.type = TransactionRecord::PrivateSendMakeCollaterals;
if(wallet->IsDenominatedAmount(txout.nValue)) sub.type = TransactionRecord::PrivateSendCreateDenominations; if(CPrivateSend::IsDenominatedAmount(txout.nValue)) sub.type = TransactionRecord::PrivateSendCreateDenominations;
if(nDebit - wtx.GetValueOut() == CPrivateSend::GetCollateralAmount()) sub.type = TransactionRecord::PrivateSendCollateralPayment; if(nDebit - wtx.GetValueOut() == CPrivateSend::GetCollateralAmount()) sub.type = TransactionRecord::PrivateSendCollateralPayment;
} }
} }

View File

@ -75,18 +75,19 @@ UniValue getpoolinfo(const UniValue& params, bool fHelp)
"Returns an object containing mixing pool related information.\n"); "Returns an object containing mixing pool related information.\n");
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
CPrivateSendBase privateSend = fMasterNode ? (CPrivateSendBase)privateSendServer : (CPrivateSendBase)privateSendClient; CPrivateSendBase* pprivateSendBase = fMasterNode ? (CPrivateSendBase*)&privateSendServer : (CPrivateSendBase*)&privateSendClient;
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("state", privateSend.GetStateString())); obj.push_back(Pair("state", pprivateSendBase->GetStateString()));
obj.push_back(Pair("mixing_mode", (!fMasterNode && privateSendClient.fPrivateSendMultiSession) ? "multi-session" : "normal")); obj.push_back(Pair("mixing_mode", (!fMasterNode && privateSendClient.fPrivateSendMultiSession) ? "multi-session" : "normal"));
obj.push_back(Pair("queue", privateSend.GetQueueSize())); obj.push_back(Pair("queue", pprivateSendBase->GetQueueSize()));
obj.push_back(Pair("entries", privateSend.GetEntriesCount())); obj.push_back(Pair("entries", pprivateSendBase->GetEntriesCount()));
obj.push_back(Pair("status", privateSendClient.GetStatus())); obj.push_back(Pair("status", privateSendClient.GetStatus()));
if (privateSendClient.infoMixingMasternode.fInfoValid) { masternode_info_t mnInfo;
obj.push_back(Pair("outpoint", privateSendClient.infoMixingMasternode.vin.prevout.ToStringShort())); if (privateSendClient.GetMixingMasternodeInfo(mnInfo)) {
obj.push_back(Pair("addr", privateSendClient.infoMixingMasternode.addr.ToString())); obj.push_back(Pair("outpoint", mnInfo.vin.prevout.ToStringShort()));
obj.push_back(Pair("addr", mnInfo.addr.ToString()));
} }
if (pwalletMain) { if (pwalletMain) {

View File

@ -1269,14 +1269,14 @@ int CWallet::GetRealOutpointPrivateSendRounds(const COutPoint& outpoint, int nRo
return -4; return -4;
} }
if (IsCollateralAmount(wtx->vout[nout].nValue)) { if (CPrivateSend::IsCollateralAmount(wtx->vout[nout].nValue)) {
mDenomWtxes[hash].vout[nout].nRounds = -3; mDenomWtxes[hash].vout[nout].nRounds = -3;
LogPrint("privatesend", "GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); LogPrint("privatesend", "GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds);
return mDenomWtxes[hash].vout[nout].nRounds; return mDenomWtxes[hash].vout[nout].nRounds;
} }
//make sure the final output is non-denominate //make sure the final output is non-denominate
if (!IsDenominatedAmount(wtx->vout[nout].nValue)) { //NOT DENOM if (!CPrivateSend::IsDenominatedAmount(wtx->vout[nout].nValue)) { //NOT DENOM
mDenomWtxes[hash].vout[nout].nRounds = -2; mDenomWtxes[hash].vout[nout].nRounds = -2;
LogPrint("privatesend", "GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds); LogPrint("privatesend", "GetRealOutpointPrivateSendRounds UPDATED %s %3d %3d\n", hash.ToString(), nout, mDenomWtxes[hash].vout[nout].nRounds);
return mDenomWtxes[hash].vout[nout].nRounds; return mDenomWtxes[hash].vout[nout].nRounds;
@ -1284,7 +1284,7 @@ int CWallet::GetRealOutpointPrivateSendRounds(const COutPoint& outpoint, int nRo
bool fAllDenoms = true; bool fAllDenoms = true;
BOOST_FOREACH(CTxOut out, wtx->vout) { BOOST_FOREACH(CTxOut out, wtx->vout) {
fAllDenoms = fAllDenoms && IsDenominatedAmount(out.nValue); fAllDenoms = fAllDenoms && CPrivateSend::IsDenominatedAmount(out.nValue);
} }
// this one is denominated but there is another non-denominated output found in the same tx // this one is denominated but there is another non-denominated output found in the same tx
@ -1333,21 +1333,13 @@ bool CWallet::IsDenominated(const COutPoint& outpoint) const
if (mi != mapWallet.end()) { if (mi != mapWallet.end()) {
const CWalletTx& prev = (*mi).second; const CWalletTx& prev = (*mi).second;
if (outpoint.n < prev.vout.size()) { if (outpoint.n < prev.vout.size()) {
return IsDenominatedAmount(prev.vout[outpoint.n].nValue); return CPrivateSend::IsDenominatedAmount(prev.vout[outpoint.n].nValue);
} }
} }
return false; return false;
} }
bool CWallet::IsDenominatedAmount(CAmount nInputAmount) const
{
BOOST_FOREACH(CAmount d, CPrivateSend::GetStandardDenominations())
if(nInputAmount == d)
return true;
return false;
}
isminetype CWallet::IsMine(const CTxOut& txout) const isminetype CWallet::IsMine(const CTxOut& txout) const
{ {
return ::IsMine(*this, txout.scriptPubKey); return ::IsMine(*this, txout.scriptPubKey);
@ -2003,7 +1995,7 @@ CAmount CWalletTx::GetDenominatedCredit(bool unconfirmed, bool fUseCache) const
{ {
const CTxOut &txout = vout[i]; const CTxOut &txout = vout[i];
if(pwallet->IsSpent(hashTx, i) || !pwallet->IsDenominatedAmount(vout[i].nValue)) continue; if(pwallet->IsSpent(hashTx, i) || !CPrivateSend::IsDenominatedAmount(vout[i].nValue)) continue;
nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE); nCredit += pwallet->GetCredit(txout, ISMINE_SPENDABLE);
if (!MoneyRange(nCredit)) if (!MoneyRange(nCredit))
@ -2164,7 +2156,7 @@ CAmount CWallet::GetAnonymizableBalance(bool fSkipDenominated, bool fSkipUnconfi
const CAmount nSmallestDenom = CPrivateSend::GetSmallestDenomination(); const CAmount nSmallestDenom = CPrivateSend::GetSmallestDenomination();
const CAmount nMixingCollateral = CPrivateSend::GetCollateralAmount(); const CAmount nMixingCollateral = CPrivateSend::GetCollateralAmount();
BOOST_FOREACH(CompactTallyItem& item, vecTally) { BOOST_FOREACH(CompactTallyItem& item, vecTally) {
bool fIsDenominated = IsDenominatedAmount(item.nAmount); bool fIsDenominated = CPrivateSend::IsDenominatedAmount(item.nAmount);
if(fSkipDenominated && fIsDenominated) continue; if(fSkipDenominated && fIsDenominated) continue;
// assume that the fee to create denoms should be mixing collateral at max // assume that the fee to create denoms should be mixing collateral at max
if(item.nAmount >= nSmallestDenom + (fIsDenominated ? 0 : nMixingCollateral)) if(item.nAmount >= nSmallestDenom + (fIsDenominated ? 0 : nMixingCollateral))
@ -2390,14 +2382,14 @@ void CWallet::AvailableCoins(vector<COutput>& vCoins, bool fOnlyConfirmed, const
for (unsigned int i = 0; i < pcoin->vout.size(); i++) { for (unsigned int i = 0; i < pcoin->vout.size(); i++) {
bool found = false; bool found = false;
if(nCoinType == ONLY_DENOMINATED) { if(nCoinType == ONLY_DENOMINATED) {
found = IsDenominatedAmount(pcoin->vout[i].nValue); found = CPrivateSend::IsDenominatedAmount(pcoin->vout[i].nValue);
} else if(nCoinType == ONLY_NONDENOMINATED) { } else if(nCoinType == ONLY_NONDENOMINATED) {
if (IsCollateralAmount(pcoin->vout[i].nValue)) continue; // do not use collateral amounts if (CPrivateSend::IsCollateralAmount(pcoin->vout[i].nValue)) continue; // do not use collateral amounts
found = !IsDenominatedAmount(pcoin->vout[i].nValue); found = !CPrivateSend::IsDenominatedAmount(pcoin->vout[i].nValue);
} else if(nCoinType == ONLY_1000) { } else if(nCoinType == ONLY_1000) {
found = pcoin->vout[i].nValue == 1000*COIN; found = pcoin->vout[i].nValue == 1000*COIN;
} else if(nCoinType == ONLY_PRIVATESEND_COLLATERAL) { } else if(nCoinType == ONLY_PRIVATESEND_COLLATERAL) {
found = IsCollateralAmount(pcoin->vout[i].nValue); found = CPrivateSend::IsCollateralAmount(pcoin->vout[i].nValue);
} else { } else {
found = true; found = true;
} }
@ -2531,7 +2523,7 @@ bool CWallet::SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int
int i = output.i; int i = output.i;
CAmount n = pcoin->vout[i].nValue; CAmount n = pcoin->vout[i].nValue;
if (tryDenom == 0 && IsDenominatedAmount(n)) continue; // we don't want denom values on first run if (tryDenom == 0 && CPrivateSend::IsDenominatedAmount(n)) continue; // we don't want denom values on first run
pair<CAmount,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i)); pair<CAmount,pair<const CWalletTx*,unsigned int> > coin = make_pair(n,make_pair(pcoin, i));
@ -2756,9 +2748,9 @@ bool CWallet::FundTransaction(CMutableTransaction& tx, CAmount &nFeeRet, int& nC
return true; return true;
} }
bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector<CTxIn>& vecTxInRet, std::vector<COutput>& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax) bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector<CTxDSIn>& vecTxDSInRet, std::vector<COutput>& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax)
{ {
vecTxInRet.clear(); vecTxDSInRet.clear();
vCoinsRet.clear(); vCoinsRet.clear();
nValueRet = 0; nValueRet = 0;
@ -2801,11 +2793,10 @@ bool CWallet::SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount
nValueMax -= insecureRand(nValueMax/5); nValueMax -= insecureRand(nValueMax/5);
//on average use 50% of the inputs or less //on average use 50% of the inputs or less
int r = insecureRand(vCoins.size()); int r = insecureRand(vCoins.size());
if((int)vecTxInRet.size() > r) return true; if((int)vecTxDSInRet.size() > r) return true;
} }
txin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey
nValueRet += out.tx->vout[out.i].nValue; nValueRet += out.tx->vout[out.i].nValue;
vecTxInRet.push_back(txin); vecTxDSInRet.push_back(CTxDSIn(txin, out.tx->vout[out.i].scriptPubKey));
vCoinsRet.push_back(out); vCoinsRet.push_back(out);
nDenomResult |= 1 << nBit; nDenomResult |= 1 << nBit;
} }
@ -2872,11 +2863,11 @@ bool CWallet::SelectCoinsGrouppedByAddresses(std::vector<CompactTallyItem>& vecT
if(IsSpent(outpoint.hash, i) || IsLockedCoin(outpoint.hash, i)) continue; if(IsSpent(outpoint.hash, i) || IsLockedCoin(outpoint.hash, i)) continue;
if(fSkipDenominated && IsDenominatedAmount(wtx.vout[i].nValue)) continue; if(fSkipDenominated && CPrivateSend::IsDenominatedAmount(wtx.vout[i].nValue)) continue;
if(fAnonymizable) { if(fAnonymizable) {
// ignore collaterals // ignore collaterals
if(IsCollateralAmount(wtx.vout[i].nValue)) continue; if(CPrivateSend::IsCollateralAmount(wtx.vout[i].nValue)) continue;
if(fMasterNode && wtx.vout[i].nValue == 1000*COIN) continue; if(fMasterNode && wtx.vout[i].nValue == 1000*COIN) continue;
// ignore outputs that are 10 times smaller then the smallest denomination // ignore outputs that are 10 times smaller then the smallest denomination
// otherwise they will just lead to higher fee / lower priority // otherwise they will just lead to higher fee / lower priority
@ -2942,7 +2933,7 @@ bool CWallet::SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector<
//do not allow inputs less than 1/10th of minimum value //do not allow inputs less than 1/10th of minimum value
if(out.tx->vout[out.i].nValue < nValueMin/10) continue; if(out.tx->vout[out.i].nValue < nValueMin/10) continue;
//do not allow collaterals to be selected //do not allow collaterals to be selected
if(IsCollateralAmount(out.tx->vout[out.i].nValue)) continue; if(CPrivateSend::IsCollateralAmount(out.tx->vout[out.i].nValue)) continue;
if(fMasterNode && out.tx->vout[out.i].nValue == 1000*COIN) continue; //masternode input if(fMasterNode && out.tx->vout[out.i].nValue == 1000*COIN) continue; //masternode input
if(nValueRet + out.tx->vout[out.i].nValue <= nValueMax){ if(nValueRet + out.tx->vout[out.i].nValue <= nValueMax){
@ -2952,7 +2943,6 @@ bool CWallet::SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector<
if(nRounds >= nPrivateSendRoundsMax) continue; if(nRounds >= nPrivateSendRoundsMax) continue;
if(nRounds < nPrivateSendRoundsMin) continue; if(nRounds < nPrivateSendRoundsMin) continue;
txin.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey
nValueRet += out.tx->vout[out.i].nValue; nValueRet += out.tx->vout[out.i].nValue;
vecTxInRet.push_back(txin); vecTxInRet.push_back(txin);
} }
@ -2961,7 +2951,7 @@ bool CWallet::SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector<
return nValueRet >= nValueMin; return nValueRet >= nValueMin;
} }
bool CWallet::GetCollateralTxIn(CTxIn& txinRet, CAmount& nValueRet) const bool CWallet::GetCollateralTxDSIn(CTxDSIn& txdsinRet, CAmount& nValueRet) const
{ {
vector<COutput> vCoins; vector<COutput> vCoins;
@ -2969,10 +2959,9 @@ bool CWallet::GetCollateralTxIn(CTxIn& txinRet, CAmount& nValueRet) const
BOOST_FOREACH(const COutput& out, vCoins) BOOST_FOREACH(const COutput& out, vCoins)
{ {
if(IsCollateralAmount(out.tx->vout[out.i].nValue)) if(CPrivateSend::IsCollateralAmount(out.tx->vout[out.i].nValue))
{ {
txinRet = CTxIn(out.tx->GetHash(), out.i); txdsinRet = CTxDSIn(CTxIn(out.tx->GetHash(), out.i), out.tx->vout[out.i].scriptPubKey);
txinRet.prevPubKey = out.tx->vout[out.i].scriptPubKey; // the inputs PubKey
nValueRet = out.tx->vout[out.i].nValue; nValueRet = out.tx->vout[out.i].nValue;
return true; return true;
} }
@ -3054,7 +3043,7 @@ int CWallet::CountInputsWithAmount(CAmount nInputAmount)
COutPoint outpoint = COutPoint(out.tx->GetHash(), out.i); COutPoint outpoint = COutPoint(out.tx->GetHash(), out.i);
if(out.tx->vout[out.i].nValue != nInputAmount) continue; if(out.tx->vout[out.i].nValue != nInputAmount) continue;
if(!IsDenominatedAmount(pcoin->vout[i].nValue)) continue; if(!CPrivateSend::IsDenominatedAmount(pcoin->vout[i].nValue)) continue;
if(IsSpent(out.tx->GetHash(), i) || IsMine(pcoin->vout[i]) != ISMINE_SPENDABLE || !IsDenominated(outpoint)) continue; if(IsSpent(out.tx->GetHash(), i) || IsMine(pcoin->vout[i]) != ISMINE_SPENDABLE || !IsDenominated(outpoint)) continue;
nTotal++; nTotal++;
@ -3074,14 +3063,6 @@ bool CWallet::HasCollateralInputs(bool fOnlyConfirmed) const
return !vCoins.empty(); return !vCoins.empty();
} }
bool CWallet::IsCollateralAmount(CAmount nInputAmount) const
{
// collateral inputs should always be a 2x..4x of mixing collateral
return nInputAmount > CPrivateSend::GetCollateralAmount() &&
nInputAmount <= CPrivateSend::GetMaxCollateralAmount() &&
nInputAmount % CPrivateSend::GetCollateralAmount() == 0;
}
bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason) bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason)
{ {
txCollateral.vin.clear(); txCollateral.vin.clear();
@ -3089,9 +3070,9 @@ bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std
CReserveKey reservekey(this); CReserveKey reservekey(this);
CAmount nValue = 0; CAmount nValue = 0;
CTxIn txinCollateral; CTxDSIn txdsinCollateral;
if (!GetCollateralTxIn(txinCollateral, nValue)) { if (!GetCollateralTxDSIn(txdsinCollateral, nValue)) {
strReason = "PrivateSend requires a collateral transaction and could not locate an acceptable input!"; strReason = "PrivateSend requires a collateral transaction and could not locate an acceptable input!";
return false; return false;
} }
@ -3103,13 +3084,13 @@ bool CWallet::CreateCollateralTransaction(CMutableTransaction& txCollateral, std
scriptChange = GetScriptForDestination(vchPubKey.GetID()); scriptChange = GetScriptForDestination(vchPubKey.GetID());
reservekey.KeepKey(); reservekey.KeepKey();
txCollateral.vin.push_back(txinCollateral); txCollateral.vin.push_back(txdsinCollateral);
//pay collateral charge in fees //pay collateral charge in fees
CTxOut txout = CTxOut(nValue - CPrivateSend::GetCollateralAmount(), scriptChange); CTxOut txout = CTxOut(nValue - CPrivateSend::GetCollateralAmount(), scriptChange);
txCollateral.vout.push_back(txout); txCollateral.vout.push_back(txout);
if(!SignSignature(*this, txinCollateral.prevPubKey, txCollateral, 0, int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))) { if(!SignSignature(*this, txdsinCollateral.prevPubKey, txCollateral, 0, int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))) {
strReason = "Unable to sign collateral transaction!"; strReason = "Unable to sign collateral transaction!";
return false; return false;
} }
@ -3409,14 +3390,16 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// //
// Note how the sequence number is set to max()-1 so that the // Note how the sequence number is set to max()-1 so that the
// nLockTime set above actually works. // nLockTime set above actually works.
std::vector<CTxDSIn> vecTxDSInTmp;
BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins){ BOOST_FOREACH(const PAIRTYPE(const CWalletTx*,unsigned int)& coin, setCoins){
CTxIn txin = CTxIn(coin.first->GetHash(),coin.second,CScript(), CTxIn txin = CTxIn(coin.first->GetHash(),coin.second,CScript(),
std::numeric_limits<unsigned int>::max()-1); std::numeric_limits<unsigned int>::max()-1);
txin.prevPubKey = coin.first->vout[coin.second].scriptPubKey; vecTxDSInTmp.push_back(CTxDSIn(txin, coin.first->vout[coin.second].scriptPubKey));
txNew.vin.push_back(txin); txNew.vin.push_back(txin);
} }
sort(txNew.vin.begin(), txNew.vin.end(), CompareInputBIP69()); sort(txNew.vin.begin(), txNew.vin.end(), CompareInputBIP69());
sort(vecTxDSInTmp.begin(), vecTxDSInTmp.end(), CompareInputBIP69());
sort(txNew.vout.begin(), txNew.vout.end(), CompareOutputBIP69()); sort(txNew.vout.begin(), txNew.vout.end(), CompareOutputBIP69());
// If there was change output added before, we must update its position now // If there was change output added before, we must update its position now
@ -3436,10 +3419,10 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend, CWalletTx& wt
// Sign // Sign
int nIn = 0; int nIn = 0;
CTransaction txNewConst(txNew); CTransaction txNewConst(txNew);
BOOST_FOREACH(const CTxIn& txin, txNew.vin) for (const auto& txdsin : vecTxDSInTmp)
{ {
bool signSuccess; bool signSuccess;
const CScript& scriptPubKey = txin.prevPubKey; const CScript& scriptPubKey = txdsin.prevPubKey;
CScript& scriptSigRes = txNew.vin[nIn].scriptSig; CScript& scriptSigRes = txNew.vin[nIn].scriptSig;
if (sign) if (sign)
signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes); signSuccess = ProduceSignature(TransactionSignatureCreator(this, &txNewConst, nIn, SIGHASH_ALL), scriptPubKey, scriptSigRes);

View File

@ -19,6 +19,8 @@
#include "wallet/wallet_ismine.h" #include "wallet/wallet_ismine.h"
#include "wallet/walletdb.h" #include "wallet/walletdb.h"
#include "privatesend.h"
#include <algorithm> #include <algorithm>
#include <map> #include <map>
#include <set> #include <set>
@ -770,9 +772,11 @@ public:
*/ */
bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool fUseInstantSend = false) const; bool SelectCoinsMinConf(const CAmount& nTargetValue, int nConfMine, int nConfTheirs, std::vector<COutput> vCoins, std::set<std::pair<const CWalletTx*,unsigned int> >& setCoinsRet, CAmount& nValueRet, bool fUseInstantSend = false) const;
bool SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector<CTxIn>& vecTxInRet, std::vector<COutput>& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax); // Coin selection
bool GetCollateralTxIn(CTxIn& txinRet, CAmount& nValueRet) const; bool SelectCoinsByDenominations(int nDenom, CAmount nValueMin, CAmount nValueMax, std::vector<CTxDSIn>& vecTxDSInRet, std::vector<COutput>& vCoinsRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax);
bool GetCollateralTxDSIn(CTxDSIn& txdsinRet, CAmount& nValueRet) const;
bool SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector<CTxIn>& vecTxInRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax) const; bool SelectCoinsDark(CAmount nValueMin, CAmount nValueMax, std::vector<CTxIn>& vecTxInRet, CAmount& nValueRet, int nPrivateSendRoundsMin, int nPrivateSendRoundsMax) const;
bool SelectCoinsGrouppedByAddresses(std::vector<CompactTallyItem>& vecTallyRet, bool fSkipDenominated = true, bool fAnonymizable = true, bool fSkipUnconfirmed = true) const; bool SelectCoinsGrouppedByAddresses(std::vector<CompactTallyItem>& vecTallyRet, bool fSkipDenominated = true, bool fAnonymizable = true, bool fSkipUnconfirmed = true) const;
/// Get 1000DASH output and keys which can be used for the Masternode /// Get 1000DASH output and keys which can be used for the Masternode
@ -781,7 +785,6 @@ public:
bool GetOutpointAndKeysFromOutput(const COutput& out, COutPoint& outpointRet, CPubKey& pubKeyRet, CKey& keyRet); bool GetOutpointAndKeysFromOutput(const COutput& out, COutPoint& outpointRet, CPubKey& pubKeyRet, CKey& keyRet);
bool HasCollateralInputs(bool fOnlyConfirmed = true) const; bool HasCollateralInputs(bool fOnlyConfirmed = true) const;
bool IsCollateralAmount(CAmount nInputAmount) const;
int CountInputsWithAmount(CAmount nInputAmount); int CountInputsWithAmount(CAmount nInputAmount);
// get the PrivateSend chain depth for a given input // get the PrivateSend chain depth for a given input
@ -790,7 +793,6 @@ public:
int GetOutpointPrivateSendRounds(const COutPoint& outpoint) const; int GetOutpointPrivateSendRounds(const COutPoint& outpoint) const;
bool IsDenominated(const COutPoint& outpoint) const; bool IsDenominated(const COutPoint& outpoint) const;
bool IsDenominatedAmount(CAmount nInputAmount) const;
bool IsSpent(const uint256& hash, unsigned int n) const; bool IsSpent(const uint256& hash, unsigned int n) const;