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:
parent
c166ed39b0
commit
7e96af4e65
@ -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"
|
||||||
|
|
||||||
|
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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. */
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user