diff --git a/src/Makefile.am b/src/Makefile.am index 6c0713dd93..9615f89f2e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,6 +41,7 @@ BITCOIN_CORE_H = \ core.h \ crypter.h \ darksend.h \ + darksend-relay.h \ db.h \ hash.h \ init.h \ @@ -151,6 +152,7 @@ libdarkcoin_common_a_SOURCES = \ chainparams.cpp \ core.cpp \ darksend.cpp \ + darksend-relay.cpp \ masternode.cpp \ masternodeman.cpp \ masternodeconfig.cpp \ diff --git a/src/activemasternode.cpp b/src/activemasternode.cpp index d7b48900ad..30d9de8b75 100644 --- a/src/activemasternode.cpp +++ b/src/activemasternode.cpp @@ -217,8 +217,8 @@ bool CActiveMasternode::Dseep(CTxIn vin, CService service, CKey keyMasternode, C } //send to all peers - LogPrintf("CActiveMasternode::Dseep() - SendDarkSendElectionEntryPing vin = %s\n", vin.ToString().c_str()); - SendDarkSendElectionEntryPing(vin, vchMasterNodeSignature, masterNodeSignatureTime, stop); + LogPrintf("CActiveMasternode::Dseep() - RelayMasternodeEntryPing vin = %s\n", vin.ToString().c_str()); + mnodeman.RelayMasternodeEntryPing(vin, vchMasterNodeSignature, masterNodeSignatureTime, stop); return true; } @@ -277,8 +277,8 @@ bool CActiveMasternode::Register(CTxIn vin, CService service, CKey keyCollateral } //send to all peers - LogPrintf("CActiveMasternode::Register() - SendDarkSendElectionEntry vin = %s\n", vin.ToString().c_str()); - SendDarkSendElectionEntry(vin, service, vchMasterNodeSignature, masterNodeSignatureTime, pubKeyCollateralAddress, pubKeyMasternode, -1, -1, masterNodeSignatureTime, PROTOCOL_VERSION); + LogPrintf("CActiveMasternode::Register() - RelayElectionEntry vin = %s\n", vin.ToString().c_str()); + mnodeman.RelayMasternodeEntry(vin, service, vchMasterNodeSignature, masterNodeSignatureTime, pubKeyCollateralAddress, pubKeyMasternode, -1, -1, masterNodeSignatureTime, PROTOCOL_VERSION); return true; } diff --git a/src/coincontrol.h b/src/coincontrol.h index 97c30c2713..6e47a09730 100644 --- a/src/coincontrol.h +++ b/src/coincontrol.h @@ -12,6 +12,8 @@ class CCoinControl { public: CTxDestination destChange; + bool useDarkSend; + bool useInstantX; CCoinControl() { @@ -22,6 +24,8 @@ public: { destChange = CNoDestination(); setSelected.clear(); + useInstantX = false; + useDarkSend = true; } bool HasSelected() const diff --git a/src/core.h b/src/core.h index e06441dd1c..ac4ddda9ea 100644 --- a/src/core.h +++ b/src/core.h @@ -43,6 +43,8 @@ static const int64_t DARKSEND_POOL_MAX = (999.99*COIN); #define MASTERNODE_EXPIRATION_SECONDS (65*60) #define MASTERNODE_REMOVAL_SECONDS (70*60) +static const int MIN_POOL_PEER_PROTO_VERSION = 70067; // minimum peer version accepted by DarkSendPool + class CTransaction; /** No amount larger than this (in satoshi) is valid */ diff --git a/src/darksend-relay.cpp b/src/darksend-relay.cpp new file mode 100644 index 0000000000..abe4eb1fe2 --- /dev/null +++ b/src/darksend-relay.cpp @@ -0,0 +1,132 @@ + +#include "darksend-relay.h" + + +CDarkSendRelay::CDarkSendRelay() +{ + vinMasternode = CTxIn(); + nBlockHeight = 0; + nRelayType = 0; + in = CTxIn(); + out = CTxOut(); + strSharedKey = ""; +} + +CDarkSendRelay::CDarkSendRelay(CTxIn& vinMasternodeIn, vector& vchSigIn, int nBlockHeightIn, int nRelayTypeIn, CTxIn& in2, CTxOut& out2, std::string strSharedKeyIn) +{ + vinMasternode = vinMasternodeIn; + vchSig = vchSigIn; + nBlockHeight = nBlockHeightIn; + nRelayType = nRelayTypeIn; + in = in2; + out = out2; + strSharedKey = strSharedKeyIn; +} + +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() +{ + if(!fMasterNode) return false; + + std::string strMessage = in.ToString() + out.ToString(); + + CKey key2; + CPubKey pubkey2; + std::string errorMessage = ""; + + if(!darkSendSigner.SetKey(strSharedKey, errorMessage, key2, pubkey2)) + { + LogPrintf("CDarkSendRelay():Relay - ERROR: Invalid masternodeprivkey: '%s'\n", errorMessage.c_str()); + return false; + } + + if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig2, key2)) { + LogPrintf("CDarkSendRelay():Relay - Sign message failed"); + return false; + } + + if(!darkSendSigner.VerifyMessage(pubkey2, vchSig, strMessage, errorMessage)) { + LogPrintf("CDarkSendRelay():Relay - Verify message failed"); + return false; + } + + return true; +} + +bool CDarkSendRelay::VerifyMessage(std::string strSharedKey) +{ + if(!fMasterNode) return false; + + std::string strMessage = in.ToString() + out.ToString(); + + CKey key2; + CPubKey pubkey2; + std::string errorMessage = ""; + + if(!darkSendSigner.SetKey(strSharedKey, errorMessage, key2, pubkey2)) + { + LogPrintf("CDarkSendRelay():Relay - ERROR: Invalid masternodeprivkey: '%s'\n", errorMessage.c_str()); + return false; + } + + if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchSig2, key2)) { + LogPrintf("CDarkSendRelay():Relay - Sign message failed"); + return false; + } + + if(!darkSendSigner.VerifyMessage(pubkey2, vchSig, strMessage, errorMessage)) { + LogPrintf("CDarkSendRelay():Relay - Verify message failed"); + return false; + } + + return true; +} + +void CDarkSendRelay::Relay() +{ + int nCount = std::min(mnodeman.CountEnabled(), 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) +{ + CMasternode* pmn = mnodeman.GetMasternodeByRank(nRank, nBlockHeight, MIN_POOL_PEER_PROTO_VERSION); + + if(pmn){ + //printf("RelayThroughNode %s\n", pmn->addr.ToString().c_str()); + if(ConnectNode((CAddress)pmn->addr, NULL, true)){ + //printf("Connected\n"); + CNode* pNode = FindNode(pmn->addr); + if(pNode) + { + //printf("Found\n"); + pNode->PushMessage("dsr", (*this)); + return; + } + } + } else { + //printf("RelayThroughNode NULL\n"); + } +} \ No newline at end of file diff --git a/src/darksend-relay.h b/src/darksend-relay.h new file mode 100644 index 0000000000..f711cec726 --- /dev/null +++ b/src/darksend-relay.h @@ -0,0 +1,51 @@ + +// Copyright (c) 2014-2015 The Darkcoin 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 "core.h" +#include "main.h" +#include "activemasternode.h" +#include "masternodeman.h" + + +class CDarkSendRelay +{ +public: + CTxIn vinMasternode; + vector vchSig; + vector vchSig2; + int nBlockHeight; + int nRelayType; + CTxIn in; + CTxOut out; + std::string strSharedKey; + + CDarkSendRelay(); + CDarkSendRelay(CTxIn& vinMasternodeIn, vector& vchSigIn, int nBlockHeightIn, int nRelayTypeIn, CTxIn& in2, CTxOut& out2, std::string strSharedKeyIn); + + IMPLEMENT_SERIALIZE + ( + READWRITE(vinMasternode); + READWRITE(vchSig); + READWRITE(vchSig2); + READWRITE(nBlockHeight); + READWRITE(nRelayType); + READWRITE(in); + READWRITE(out); + ) + + std::string ToString(); + + bool Sign(); + bool VerifyMessage(std::string strSharedKey); + void Relay(); + void RelayThroughNode(int nRank); +}; + + + +#endif \ No newline at end of file diff --git a/src/darksend.cpp b/src/darksend.cpp index ba14fd5f44..068a10a398 100644 --- a/src/darksend.cpp +++ b/src/darksend.cpp @@ -2,10 +2,6 @@ // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#if defined(HAVE_CONFIG_H) -#include "darkcoin-config.h" -#endif - #include "darksend.h" #include "main.h" #include "init.h" @@ -28,7 +24,7 @@ using namespace boost; CCriticalSection cs_darksend; /** The main object for accessing darksend */ -CDarkSendPool darkSendPool; +CDarksendPool darkSendPool; /** A helper object for signing messages from masternodes */ CDarkSendSigner darkSendSigner; /** The current darksends in progress on the network */ @@ -46,65 +42,20 @@ int RequestedMasterNodeList = 0; /* *** BEGIN DARKSEND MAGIC - DARKCOIN ********** Copyright 2014, Darkcoin Developers eduffield - evan@darkcoin.io + udjinm6 - udjinm6@darkcoin.io */ -void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) +void CDarksendPool::ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) { if(fLiteMode) return; //disable all darksend/masternode related functionality if(IsInitialBlockDownload()) return; - if (strCommand == "dsf") { //DarkSend Final tx - if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { - return; - } - - if((CNetAddr)darkSendPool.submittedToMasternode != (CNetAddr)pfrom->addr){ - //LogPrintf("dsc - message doesn't match current masternode - %s != %s\n", darkSendPool.submittedToMasternode.ToString().c_str(), pfrom->addr.ToString().c_str()); - return; - } - - int sessionID; - CTransaction txNew; - vRecv >> sessionID >> txNew; - - if(darkSendPool.sessionID != sessionID){ - if (fDebug) LogPrintf("dsf - message doesn't match current darksend session %d %d\n", darkSendPool.sessionID, sessionID); - return; - } - - //check to see if input is spent already? (and probably not confirmed) - darkSendPool.SignFinalTransaction(txNew, pfrom); - } - - else if (strCommand == "dsc") { //DarkSend Complete - if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { - return; - } - - if((CNetAddr)darkSendPool.submittedToMasternode != (CNetAddr)pfrom->addr){ - //LogPrintf("dsc - message doesn't match current masternode - %s != %s\n", darkSendPool.submittedToMasternode.ToString().c_str(), pfrom->addr.ToString().c_str()); - return; - } - - int sessionID; - bool error; - std::string lastMessage; - vRecv >> sessionID >> error >> lastMessage; - - if(darkSendPool.sessionID != sessionID){ - if (fDebug) LogPrintf("dsc - message doesn't match current darksend session %d %d\n", darkSendPool.sessionID, sessionID); - return; - } - - darkSendPool.CompletedTransaction(error, lastMessage); - } - - else if (strCommand == "dsa") { //DarkSend Acceptable + if (strCommand == "dsa") { //DarkSend Accept Into Pool if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { std::string strError = _("Incompatible version."); LogPrintf("dsa -- incompatible version! \n"); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, strError); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, strError); return; } @@ -112,7 +63,7 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& if(!fMasterNode){ std::string strError = _("This is not a masternode."); LogPrintf("dsa -- not a masternode! \n"); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, strError); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, strError); return; } @@ -126,31 +77,33 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& if(pmn == NULL) { std::string strError = _("Not in the masternode list."); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, strError); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, strError); return; } - if(darkSendPool.sessionUsers == 0) { + if(sessionUsers == 0) { if(pmn->nLastDsq != 0 && - pmn->nLastDsq + mnodeman.CountMasternodesAboveProtocol(MIN_POOL_PEER_PROTO_VERSION)/5 > darkSendPool.nDsqCount){ + pmn->nLastDsq + mnodeman.CountMasternodesAboveProtocol(MIN_POOL_PEER_PROTO_VERSION)/5 > nDsqCount){ LogPrintf("dsa -- last dsq too recent, must wait. %s \n", pmn->addr.ToString().c_str()); std::string strError = _("Last Darksend was too recent."); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, strError); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, strError); return; } } - if(!darkSendPool.IsCompatibleWithSession(nDenom, txCollateral, error)) + if(!IsCompatibleWithSession(nDenom, txCollateral, error)) { LogPrintf("dsa -- not compatible with existing transactions! \n"); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); return; } else { LogPrintf("dsa -- is compatible, please submit! \n"); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_ACCEPTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_ACCEPTED, error); return; } + } else if (strCommand == "dsq") { //DarkSend Queue + LOCK(cs_darksend); if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { return; @@ -159,7 +112,6 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& CDarksendQueue dsq; vRecv >> dsq; - CService addr; if(!dsq.GetAddress(addr)) return; if(!dsq.CheckSignature()) return; @@ -171,27 +123,33 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& // if the queue is ready, submit if we can if(dsq.ready) { - if((CNetAddr)darkSendPool.submittedToMasternode != (CNetAddr)addr){ - LogPrintf("dsq - message doesn't match current masternode - %s != %s\n", darkSendPool.submittedToMasternode.ToString().c_str(), pfrom->addr.ToString().c_str()); + if(!pSubmittedToMasternode) return; + if((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)addr){ + LogPrintf("dsq - message doesn't match current masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString().c_str(), addr.ToString().c_str()); return; } - if (fDebug) LogPrintf("darksend queue is ready - %s\n", addr.ToString().c_str()); - darkSendPool.PrepareDarksendDenominate(); + if(state == POOL_STATUS_QUEUE){ + //save the relay signature info + AddRelaySignature(dsq.vchRelaySig, dsq.nBlockHeight, dsq.strSharedKey); + + if (fDebug) LogPrintf("darksend queue is ready - %s\n", addr.ToString().c_str()); + PrepareDarksendDenominate(); + } } else { BOOST_FOREACH(CDarksendQueue q, vecDarksendQueue){ if(q.vin == dsq.vin) return; } - if(fDebug) LogPrintf("dsq last %d last2 %d count %d\n", pmn->nLastDsq, pmn->nLastDsq + mnodeman.size()/5, darkSendPool.nDsqCount); + if(fDebug) LogPrintf("dsq last %d last2 %d count %d\n", pmn->nLastDsq, pmn->nLastDsq + mnodeman.size()/5, nDsqCount); //don't allow a few nodes to dominate the queuing process if(pmn->nLastDsq != 0 && - pmn->nLastDsq + mnodeman.CountMasternodesAboveProtocol(MIN_POOL_PEER_PROTO_VERSION)/5 > darkSendPool.nDsqCount){ + pmn->nLastDsq + mnodeman.CountMasternodesAboveProtocol(MIN_POOL_PEER_PROTO_VERSION)/5 > nDsqCount){ if(fDebug) LogPrintf("dsq -- masternode sending too many dsq messages. %s \n", pmn->addr.ToString().c_str()); return; } - darkSendPool.nDsqCount++; - pmn->nLastDsq = darkSendPool.nDsqCount; + nDsqCount++; + pmn->nLastDsq = nDsqCount; pmn->allowFreeTx = true; if(fDebug) LogPrintf("dsq - new darksend queue object - %s\n", addr.ToString().c_str()); @@ -200,12 +158,142 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& dsq.time = GetTime(); } + } else if (strCommand == "dsr") { //DarkSend Relay + + //* Ask a masternode to relay an anonymous output to another masternode *// + + std::string error = ""; + if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { + LogPrintf("dsr -- incompatible version! \n"); + return; + } + + if(!fMasterNode){ + LogPrintf("dsr -- not a masternode! \n"); + return; + } + + CDarkSendRelay dsr; + vRecv >> dsr; + + if(chainActive.Tip()->nHeight - dsr.nBlockHeight > 10) return; + + if(dsr.nRelayType != DARKSEND_RELAY_IN && + dsr.nRelayType != DARKSEND_RELAY_OUT && + dsr.nRelayType != DARKSEND_RELAY_SIG) return; + + + if(dsr.in == CTxIn() && dsr.nRelayType == DARKSEND_RELAY_IN) return; + if(dsr.out == CTxOut() && dsr.nRelayType == DARKSEND_RELAY_OUT) return; + if(dsr.in == CTxIn() && dsr.nRelayType == DARKSEND_RELAY_SIG) return; + + CMasternode* pmn = mnodeman.Find(dsr.vinMasternode); + if(!pmn){ + LogPrintf("dsr -- unknown masternode! %s \n", dsr.vinMasternode.ToString().c_str()); + return; + } + + int a = mnodeman.GetMasternodeRank(activeMasternode.vin, chainActive.Tip()->nHeight, MIN_POOL_PEER_PROTO_VERSION); + + if(a > 20){ + LogPrintf("dsr -- unknown/invalid masternode! %s \n", activeMasternode.vin.ToString().c_str()); + return; + } + + //check the signature from the target masternode + std::string strMessage = boost::lexical_cast(dsr.nBlockHeight); + std::string errorMessage = ""; + if(!darkSendSigner.VerifyMessage(pmn->pubkey2, dsr.vchSig, strMessage, errorMessage)){ + LogPrintf("dsr - Got bad masternode address signature\n"); + Misbehaving(pfrom->GetId(), 100); + return; + } + + //connect and deliver the message + if(ConnectNode((CAddress)pmn->addr, NULL, true)){ + CNode* pNode = FindNode(pmn->addr); + if(pNode) + { + pNode->PushMessage("dsai", dsr); + return; + } + } + + } else if (strCommand == "dsai") { //DarkSend Anonymous Item (Input/Output/Sig) + + std::string error = ""; + if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { + LogPrintf("dsai -- incompatible version! \n"); + return; + } + + if(!fMasterNode){ + LogPrintf("dsai -- not a masternode! \n"); + return; + } + + CDarkSendRelay dsr; + vRecv >> dsr; + + if(chainActive.Tip()->nHeight - dsr.nBlockHeight > 10) return; + if(darkSendPool.strMasternodeSharedKey == "") return; + if(dsr.nRelayType != DARKSEND_RELAY_IN && + dsr.nRelayType != DARKSEND_RELAY_OUT && + dsr.nRelayType != DARKSEND_RELAY_SIG) return; + if(dsr.in == CTxIn() && dsr.nRelayType == DARKSEND_RELAY_IN) return; + if(dsr.out == CTxOut() && dsr.nRelayType == DARKSEND_RELAY_OUT) return; + if(dsr.in == CTxIn() && dsr.nRelayType == DARKSEND_RELAY_SIG) return; + + CMasternode* pmn = mnodeman.Find(dsr.vinMasternode); + if(!pmn){ + LogPrintf("dsr -- unknown masternode! %s \n", dsr.vinMasternode.ToString().c_str()); + return; + } + + //check the signature from the target masternode + std::string strMessage = boost::lexical_cast(dsr.nBlockHeight); + std::string errorMessage = ""; + if(!darkSendSigner.VerifyMessage(pmn->pubkey2, dsr.vchSig, strMessage, errorMessage)){ + LogPrintf("dsr - Got bad masternode address signature\n"); + Misbehaving(pfrom->GetId(), 100); + return; + } + + if(!dsr.VerifyMessage(darkSendPool.strMasternodeSharedKey)){ + LogPrintf("dsai - Got bad shared key signature\n"); + Misbehaving(pfrom->GetId(), 30); + return; + } + + //do we have enough users in the current session? + if(!IsSessionReady()){ + LogPrintf("dsai -- session not complete! \n"); + return; + } + + switch(dsr.nRelayType){ + case DARKSEND_RELAY_IN: + anonTx.AddInput(dsr.in); + break; + case DARKSEND_RELAY_OUT: + anonTx.AddOutput(dsr.out); + break; + case DARKSEND_RELAY_SIG: + anonTx.AddSig(dsr.in); + break; + } + + // relay to all peers that an entry was added to the pool successfully. + RelayStatus(sessionID, GetState(), GetEntriesCount(), MASTERNODE_ACCEPTED); + Check(); + } else if (strCommand == "dsi") { //DarkSend vIn + std::string error = ""; if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { LogPrintf("dsi -- incompatible version! \n"); error = _("Incompatible version."); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); return; } @@ -213,7 +301,7 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& if(!fMasterNode){ LogPrintf("dsi -- not a masternode! \n"); error = _("This is not a masternode."); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); return; } @@ -225,19 +313,19 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& vRecv >> in >> nAmount >> txCollateral >> out; //do we have enough users in the current session? - if(!darkSendPool.IsSessionReady()){ + if(!IsSessionReady()){ LogPrintf("dsi -- session not complete! \n"); error = _("Session not complete!"); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); return; } //do we have the same denominations as the current session? - if(!darkSendPool.IsCompatibleWithEntries(out)) + if(!IsCompatibleWithEntries(out)) { LogPrintf("dsi -- not compatible with existing transactions! \n"); error = _("Not compatible with existing transactions."); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); return; } @@ -257,13 +345,13 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& if(o.scriptPubKey.size() != 25){ LogPrintf("dsi - non-standard pubkey detected! %s\n", o.scriptPubKey.ToString().c_str()); error = _("Non-standard public key detected."); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); return; } if(!o.scriptPubKey.IsNormalPaymentScript()){ LogPrintf("dsi - invalid script! %s\n", o.scriptPubKey.ToString().c_str()); error = _("Invalid script detected."); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); return; } } @@ -287,7 +375,7 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& if (nValueIn > DARKSEND_POOL_MAX) { LogPrintf("dsi -- more than darksend pool max! %s\n", tx.ToString().c_str()); error = _("Value more than Darksend pool maximum allows."); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); return; } @@ -295,76 +383,63 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& if (nValueIn-nValueOut > nValueIn*.01) { LogPrintf("dsi -- fees are too high! %s\n", tx.ToString().c_str()); error = _("Transaction fees are too high."); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); return; } } else { LogPrintf("dsi -- missing input tx! %s\n", tx.ToString().c_str()); error = _("Missing input transaction information."); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); return; } if(!AcceptableInputs(mempool, state, tx)){ LogPrintf("dsi -- transaction not valid! \n"); error = _("Transaction not valid."); - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); return; } } - if(darkSendPool.AddEntry(in, nAmount, txCollateral, out, error)){ - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_ACCEPTED, error); - darkSendPool.Check(); + if(AddEntry(in, nAmount, txCollateral, out, error)){ + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_ACCEPTED, error); + Check(); - RelayDarkSendStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET); + RelayStatus(sessionID, GetState(), GetEntriesCount(), MASTERNODE_RESET); } else { - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_REJECTED, error); - } - } - - else if (strCommand == "dssub") { //DarkSend Subscribe To - if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { - return; + pfrom->PushMessage("dssu", sessionID, GetState(), GetEntriesCount(), MASTERNODE_REJECTED, error); } - if(!fMasterNode) return; - - std::string error = ""; - pfrom->PushMessage("dssu", darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET, error); - return; - } - - else if (strCommand == "dssu") { //DarkSend status update + } else if (strCommand == "dssu") { //DarkSend status update if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { return; } - if((CNetAddr)darkSendPool.submittedToMasternode != (CNetAddr)pfrom->addr){ - //LogPrintf("dssu - message doesn't match current masternode - %s != %s\n", darkSendPool.submittedToMasternode.ToString().c_str(), pfrom->addr.ToString().c_str()); + if(!pSubmittedToMasternode) return; + if((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr){ + //LogPrintf("dssu - message doesn't match current masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString().c_str(), pfrom->addr.ToString().c_str()); return; } - int sessionID; + int sessionIDMessage; int state; int entriesCount; int accepted; std::string error; - vRecv >> sessionID >> state >> entriesCount >> accepted >> error; + vRecv >> sessionIDMessage >> state >> entriesCount >> accepted >> error; if(fDebug) LogPrintf("dssu - state: %i entriesCount: %i accepted: %i error: %s \n", state, entriesCount, accepted, error.c_str()); - if((accepted != 1 && accepted != 0) && darkSendPool.sessionID != sessionID){ - LogPrintf("dssu - message doesn't match current darksend session %d %d\n", darkSendPool.sessionID, sessionID); + if((accepted != 1 && accepted != 0) && sessionID != sessionIDMessage){ + LogPrintf("dssu - message doesn't match current darksend session %d %d\n", sessionID, sessionIDMessage); return; } - darkSendPool.StatusUpdate(state, entriesCount, accepted, error, sessionID); + StatusUpdate(state, entriesCount, accepted, error, sessionIDMessage); - } + } else if (strCommand == "dss") { //DarkSend Sign Final Tx - else if (strCommand == "dss") { //DarkSend Sign Final Tx if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { return; } @@ -379,15 +454,61 @@ void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& BOOST_FOREACH(const CTxIn item, sigs) { - if(darkSendPool.AddScriptSig(item)) success = true; + if(AddScriptSig(item)) success = true; if(fDebug) LogPrintf(" -- sigs count %d %d\n", (int)sigs.size(), count); count++; } if(success){ - darkSendPool.Check(); - RelayDarkSendStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET); + CheckFinalTransaction(); + RelayStatus(sessionID, GetState(), GetEntriesCount(), MASTERNODE_RESET); } + } else if (strCommand == "dsf") { //DarkSend Final tx + if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { + return; + } + + if(!pSubmittedToMasternode) return; + if((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr){ + //LogPrintf("dsc - message doesn't match current masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString().c_str(), pfrom->addr.ToString().c_str()); + return; + } + + int sessionIDMessage; + CTransaction txNew; + vRecv >> sessionIDMessage >> txNew; + + if(sessionID != sessionIDMessage){ + if (fDebug) LogPrintf("dsf - message doesn't match current darksend session %d %d\n", sessionID, sessionIDMessage); + return; + } + + //check to see if input is spent already? (and probably not confirmed) + SignFinalTransaction(txNew, pfrom); + + } else if (strCommand == "dsc") { //DarkSend Complete + + if (pfrom->nVersion < MIN_POOL_PEER_PROTO_VERSION) { + return; + } + + if(!pSubmittedToMasternode) return; + if((CNetAddr)pSubmittedToMasternode->addr != (CNetAddr)pfrom->addr){ + //LogPrintf("dsc - message doesn't match current masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString().c_str(), pfrom->addr.ToString().c_str()); + return; + } + + int sessionIDMessage; + bool error; + std::string lastMessage; + vRecv >> sessionIDMessage >> error >> lastMessage; + + if(sessionID != sessionIDMessage){ + if (fDebug) LogPrintf("dsc - message doesn't match current darksend session %d %d\n", darkSendPool.sessionID, sessionIDMessage); + return; + } + + darkSendPool.CompletedTransaction(error, lastMessage); } } @@ -402,7 +523,7 @@ int GetInputDarksendRounds(CTxIn in, int rounds) if(rounds >= 17) return rounds; uint256 hash = in.prevout.hash; - uint nout = in.prevout.n; + unsigned int nout = in.prevout.n; CWalletTx wtx; if(pwalletMain->GetTransaction(hash, wtx)) @@ -486,37 +607,23 @@ int GetInputDarksendRounds(CTxIn in, int rounds) return rounds-1; } -// manage the masternode connections -void CDarkSendPool::ProcessMasternodeConnections() -{ - LOCK(cs_vNodes); - - BOOST_FOREACH(CNode* pnode, vNodes) - { - //if it's our masternode, let it be - if(submittedToMasternode == pnode->addr) continue; - - if(pnode->fDarkSendMaster){ - LogPrintf("Closing masternode connection %s \n", pnode->addr.ToString().c_str()); - pnode->CloseSocketDisconnect(); - } - } -} - -void CDarkSendPool::Reset(){ +void CDarksendPool::Reset(){ cachedLastSuccess = 0; vecMasternodesUsed.clear(); UnlockCoins(); SetNull(); } -void CDarkSendPool::SetNull(bool clearEverything){ +void CDarksendPool::SetNull(bool clearEverything){ finalTransaction.vin.clear(); finalTransaction.vout.clear(); entries.clear(); + anonTx.vin.clear(); + anonTx.vout.clear(); + fResentInputsOutputs = false; - state = POOL_STATUS_ACCEPTING_ENTRIES; + state = POOL_STATUS_IDLE; lastTimeChanged = GetTimeMillis(); @@ -524,6 +631,7 @@ void CDarkSendPool::SetNull(bool clearEverything){ lastEntryAccepted = 0; countEntriesAccepted = 0; lastNewBlock = 0; + fSubmitAnonymousFailed = false; sessionUsers = 0; sessionDenom = 0; @@ -531,6 +639,9 @@ void CDarkSendPool::SetNull(bool clearEverything){ vecSessionCollateral.clear(); txCollateral = CTransaction(); + vchMasternodeRelaySig.clear(); + nMasternodeBlockHeight = 0; + if(clearEverything){ myEntries.clear(); @@ -547,11 +658,11 @@ void CDarkSendPool::SetNull(bool clearEverything){ std::srand(seed); } -bool CDarkSendPool::SetCollateralAddress(std::string strAddress){ +bool CDarksendPool::SetCollateralAddress(std::string strAddress){ CBitcoinAddress address; if (!address.SetString(strAddress)) { - LogPrintf("CDarkSendPool::SetCollateralAddress - Invalid DarkSend collateral address\n"); + LogPrintf("CDarksendPool::SetCollateralAddress - Invalid DarkSend collateral address\n"); return false; } collateralPubKey.SetDestination(address.Get()); @@ -561,7 +672,7 @@ bool CDarkSendPool::SetCollateralAddress(std::string strAddress){ // // Unlock coins after Darksend fails or succeeds // -void CDarkSendPool::UnlockCoins(){ +void CDarksendPool::UnlockCoins(){ BOOST_FOREACH(CTxIn v, lockedCoins) pwalletMain->UnlockCoin(v.prevout); @@ -571,140 +682,163 @@ void CDarkSendPool::UnlockCoins(){ // // Check the Darksend progress and send client updates if a masternode // -void CDarkSendPool::Check() +void CDarksendPool::Check() { - if(fDebug) LogPrintf("CDarkSendPool::Check()\n"); - if(fDebug) LogPrintf("CDarkSendPool::Check() - entries count %lu\n", entries.size()); + if(fDebug) LogPrintf("CDarksendPool::Check()\n"); + if(fDebug) LogPrintf("CDarksendPool::Check() - entries count %lu\n", entries.size()); + + //printf("CDarksendPool::Check() %d - %d - %d\n", state, anonTx.CountEntries(), GetTimeMillis()-lastTimeChanged); // If entries is full, then move on to the next phase - if(state == POOL_STATUS_ACCEPTING_ENTRIES && (int)entries.size() >= GetMaxPoolTransactions()) + if(state == POOL_STATUS_ACCEPTING_ENTRIES && ( + (int)entries.size() >= GetMaxPoolTransactions() || + (GetTimeMillis()-lastTimeChanged > 5000 && anonTx.CountEntries() > GetMaxPoolTransactions()*5) + )) { - if(fDebug) LogPrintf("CDarkSendPool::Check() -- ACCEPTING OUTPUTS\n"); + if(fDebug) LogPrintf("CDarksendPool::Check() -- TRYING TRANSACTION \n"); UpdateState(POOL_STATUS_FINALIZE_TRANSACTION); + nCountAttempts++; } // create the finalized transaction for distribution to the clients - if(state == POOL_STATUS_FINALIZE_TRANSACTION && finalTransaction.vin.empty() && finalTransaction.vout.empty()) { - if(fDebug) LogPrintf("CDarkSendPool::Check() -- FINALIZE TRANSACTIONS\n"); + if(state == POOL_STATUS_FINALIZE_TRANSACTION) { + if(fDebug) LogPrintf("CDarksendPool::Check() -- FINALIZE TRANSACTIONS\n"); UpdateState(POOL_STATUS_SIGNING); if (fMasterNode) { - // make our new transaction CTransaction txNew; - for(unsigned int i = 0; i < entries.size(); i++){ - BOOST_FOREACH(const CTxOut v, entries[i].vout) - txNew.vout.push_back(v); - BOOST_FOREACH(const CDarkSendEntryVin s, entries[i].sev) - txNew.vin.push_back(s.vin); + // make our new transaction + if((int)entries.size() >= GetMaxPoolTransactions()) { + for(unsigned int i = 0; i < entries.size(); i++){ + BOOST_FOREACH(const CTxOut& v, entries[i].vout) + txNew.vout.push_back(v); + + BOOST_FOREACH(const CTxDSIn& s, entries[i].sev) + txNew.vin.push_back(s); + } + + // shuffle the outputs for improved anonymity + std::random_shuffle ( txNew.vout.begin(), txNew.vout.end(), randomizeList); + } else { + BOOST_FOREACH(CTxDSIn& v, anonTx.vin) + txNew.vin.push_back((CTxIn)v); + + BOOST_FOREACH(CTxOut& v, anonTx.vout) + txNew.vout.push_back(v); } - // shuffle the outputs for improved anonymity - std::random_shuffle ( txNew.vout.begin(), txNew.vout.end(), randomizeList); if(fDebug) LogPrintf("Transaction 1: %s\n", txNew.ToString().c_str()); - SignFinalTransaction(txNew, NULL); // request signatures from clients - RelayDarkSendFinalTransaction(sessionID, txNew); + RelayFinalTransaction(sessionID, finalTransaction); } } - // collect signatures from clients + //printf("Signing Status %d %d\n", state == POOL_STATUS_SIGNING, SignaturesComplete()); // If we have all of the signatures, try to compile the transaction if(state == POOL_STATUS_SIGNING && SignaturesComplete()) { - if(fDebug) LogPrintf("CDarkSendPool::Check() -- SIGNING\n"); + if(fDebug) LogPrintf("CDarksendPool::Check() -- SIGNING\n"); UpdateState(POOL_STATUS_TRANSMISSION); - CWalletTx txNew = CWalletTx(pwalletMain, finalTransaction); - - LOCK2(cs_main, pwalletMain->cs_wallet); - { - if (fMasterNode) { //only the main node is master atm - if(fDebug) LogPrintf("Transaction 2: %s\n", txNew.ToString().c_str()); - - // See if the transaction is valid - if (!txNew.AcceptToMemoryPool(true)) - { - LogPrintf("CDarkSendPool::Check() - CommitTransaction : Error: Transaction not valid\n"); - SetNull(); - pwalletMain->Lock(); - - // not much we can do in this case - UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); - RelayDarkSendCompletedTransaction(sessionID, true, "Transaction not valid, please try again"); - return; - } - - LogPrintf("CDarkSendPool::Check() -- IS MASTER -- TRANSMITTING DARKSEND\n"); - - // sign a message - - int64_t sigTime = GetAdjustedTime(); - std::string strMessage = txNew.GetHash().ToString() + boost::lexical_cast(sigTime); - std::string strError = ""; - std::vector vchSig; - CKey key2; - CPubKey pubkey2; - - if(!darkSendSigner.SetKey(strMasterNodePrivKey, strError, key2, pubkey2)) - { - LogPrintf("CDarkSendPool::Check() - ERROR: Invalid masternodeprivkey: '%s'\n", strError.c_str()); - return; - } - - if(!darkSendSigner.SignMessage(strMessage, strError, vchSig, key2)) { - LogPrintf("CDarkSendPool::Check() - Sign message failed\n"); - return; - } - - if(!darkSendSigner.VerifyMessage(pubkey2, vchSig, strMessage, strError)) { - LogPrintf("CDarkSendPool::Check() - Verify message failed\n"); - return; - } - - if(!mapDarksendBroadcastTxes.count(txNew.GetHash())){ - CDarksendBroadcastTx dstx; - dstx.tx = txNew; - dstx.vin = activeMasternode.vin; - dstx.vchSig = vchSig; - dstx.sigTime = sigTime; - - mapDarksendBroadcastTxes.insert(make_pair(txNew.GetHash(), dstx)); - } - - // Broadcast the transaction to the network - txNew.fTimeReceivedIsTxTime = true; - txNew.RelayWalletTransaction(); - - // Tell the clients it was successful - RelayDarkSendCompletedTransaction(sessionID, false, _("Transaction created successfully.")); - - // Randomly charge clients - ChargeRandomFees(); - } - } - } - - // move on to next phase, allow 3 seconds incase the masternode wants to send us anything else - if((state == POOL_STATUS_TRANSMISSION && fMasterNode) || (state == POOL_STATUS_SIGNING && completedTransaction) ) { - if(fDebug) LogPrintf("CDarkSendPool::Check() -- COMPLETED -- RESETTING \n"); - SetNull(true); - UnlockCoins(); - if(fMasterNode) RelayDarkSendStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET); - pwalletMain->Lock(); + CheckFinalTransaction(); } // reset if we're here for 10 seconds if((state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) && GetTimeMillis()-lastTimeChanged >= 10000) { - if(fDebug) LogPrintf("CDarkSendPool::Check() -- RESETTING MESSAGE \n"); + if(fDebug) LogPrintf("CDarksendPool::Check() -- RESETTING MESSAGE \n"); SetNull(true); - if(fMasterNode) RelayDarkSendStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET); + if(fMasterNode) RelayStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET); UnlockCoins(); } } +void CDarksendPool::CheckFinalTransaction() +{ + CWalletTx txNew = CWalletTx(pwalletMain, finalTransaction); + + LOCK2(cs_main, pwalletMain->cs_wallet); + { + if (fMasterNode) { //only the main node is master atm + if(fDebug) LogPrintf("Transaction 2: %s\n", txNew.ToString().c_str()); + + // See if the transaction is valid + if (!txNew.AcceptToMemoryPool(true)) + { + if(nCountAttempts > 10) { + LogPrintf("CDarksendPool::Check() - CommitTransaction : Error: Transaction not valid\n"); + SetNull(); + pwalletMain->Lock(); + } + + // not much we can do in this case] + UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); + if(nCountAttempts > 5) RelayCompletedTransaction(sessionID, true, "Transaction not valid, please try again"); + + if(!fSubmitAnonymousFailed && nCountAttempts > 5) + fSubmitAnonymousFailed = true; + return; + } + + LogPrintf("CDarksendPool::Check() -- IS MASTER -- TRANSMITTING DARKSEND\n"); + + // sign a message + + int64_t sigTime = GetAdjustedTime(); + std::string strMessage = txNew.GetHash().ToString() + boost::lexical_cast(sigTime); + std::string strError = ""; + std::vector vchSig; + CKey key2; + CPubKey pubkey2; + + if(!darkSendSigner.SetKey(strMasterNodePrivKey, strError, key2, pubkey2)) + { + LogPrintf("CDarksendPool::Check() - ERROR: Invalid masternodeprivkey: '%s'\n", strError.c_str()); + return; + } + + if(!darkSendSigner.SignMessage(strMessage, strError, vchSig, key2)) { + LogPrintf("CDarksendPool::Check() - Sign message failed\n"); + return; + } + + if(!darkSendSigner.VerifyMessage(pubkey2, vchSig, strMessage, strError)) { + LogPrintf("CDarksendPool::Check() - Verify message failed\n"); + return; + } + + if(!mapDarksendBroadcastTxes.count(txNew.GetHash())){ + CDarksendBroadcastTx dstx; + dstx.tx = txNew; + dstx.vin = activeMasternode.vin; + dstx.vchSig = vchSig; + dstx.sigTime = sigTime; + + mapDarksendBroadcastTxes.insert(make_pair(txNew.GetHash(), dstx)); + } + + // Broadcast the transaction to the network + txNew.fTimeReceivedIsTxTime = true; + txNew.RelayWalletTransaction(); + + // Tell the clients it was successful + RelayCompletedTransaction(sessionID, false, _("Transaction created successfully.")); + + // Randomly charge clients + ChargeRandomFees(); + + // Reset + if(fDebug) LogPrintf("CDarksendPool::Check() -- COMPLETED -- RESETTING \n"); + SetNull(true); + UnlockCoins(); + if(fMasterNode) RelayStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET); + pwalletMain->Lock(); + } + } +} + // // Charge clients a fee if they're abusive // @@ -717,7 +851,7 @@ void CDarkSendPool::Check() // transaction for the client to be able to enter the pool. This transaction is kept by the masternode // until the transaction is either complete or fails. // -void CDarkSendPool::ChargeFees(){ +void CDarksendPool::ChargeFees(){ if(fMasterNode) { //we don't need to charge collateral for every offence. int offences = 0; @@ -735,7 +869,7 @@ void CDarkSendPool::ChargeFees(){ // This queue entry didn't send us the promised transaction if(!found){ - LogPrintf("CDarkSendPool::ChargeFees -- found uncooperative node (didn't send transaction). Found offence.\n"); + LogPrintf("CDarksendPool::ChargeFees -- found uncooperative node (didn't send transaction). Found offence.\n"); offences++; } } @@ -744,9 +878,9 @@ void CDarkSendPool::ChargeFees(){ if(state == POOL_STATUS_SIGNING) { // who didn't sign? BOOST_FOREACH(const CDarkSendEntry v, entries) { - BOOST_FOREACH(const CDarkSendEntryVin s, v.sev) { - if(!s.isSigSet){ - LogPrintf("CDarkSendPool::ChargeFees -- found uncooperative node (didn't sign). Found offence\n"); + BOOST_FOREACH(const CTxDSIn s, v.sev) { + if(!s.fHasSig){ + LogPrintf("CDarksendPool::ChargeFees -- found uncooperative node (didn't sign). Found offence\n"); offences++; } } @@ -779,7 +913,7 @@ void CDarkSendPool::ChargeFees(){ // This queue entry didn't send us the promised transaction if(!found && r > target){ - LogPrintf("CDarkSendPool::ChargeFees -- found uncooperative node (didn't send transaction). charging fees.\n"); + LogPrintf("CDarksendPool::ChargeFees -- found uncooperative node (didn't send transaction). charging fees.\n"); CWalletTx wtxCollateral = CWalletTx(pwalletMain, txCollateral); @@ -787,7 +921,7 @@ void CDarkSendPool::ChargeFees(){ if (!wtxCollateral.AcceptToMemoryPool(true)) { // This must not fail. The transaction has already been signed and recorded. - LogPrintf("CDarkSendPool::ChargeFees() : Error: Transaction not valid"); + LogPrintf("CDarksendPool::ChargeFees() : Error: Transaction not valid"); } wtxCollateral.RelayWalletTransaction(); return; @@ -798,9 +932,9 @@ void CDarkSendPool::ChargeFees(){ if(state == POOL_STATUS_SIGNING) { // who didn't sign? BOOST_FOREACH(const CDarkSendEntry v, entries) { - BOOST_FOREACH(const CDarkSendEntryVin s, v.sev) { - if(!s.isSigSet && r > target){ - LogPrintf("CDarkSendPool::ChargeFees -- found uncooperative node (didn't sign). charging fees.\n"); + BOOST_FOREACH(const CTxDSIn s, v.sev) { + if(!s.fHasSig && r > target){ + LogPrintf("CDarksendPool::ChargeFees -- found uncooperative node (didn't sign). charging fees.\n"); CWalletTx wtxCollateral = CWalletTx(pwalletMain, v.collateral); @@ -808,7 +942,7 @@ void CDarkSendPool::ChargeFees(){ if (!wtxCollateral.AcceptToMemoryPool(true)) { // This must not fail. The transaction has already been signed and recorded. - LogPrintf("CDarkSendPool::ChargeFees() : Error: Transaction not valid"); + LogPrintf("CDarksendPool::ChargeFees() : Error: Transaction not valid"); } wtxCollateral.RelayWalletTransaction(); return; @@ -821,7 +955,7 @@ void CDarkSendPool::ChargeFees(){ // charge the collateral randomly // - Darksend is completely free, to pay miners we randomly pay the collateral of users. -void CDarkSendPool::ChargeRandomFees(){ +void CDarksendPool::ChargeRandomFees(){ if(fMasterNode) { int i = 0; @@ -839,7 +973,7 @@ void CDarkSendPool::ChargeRandomFees(){ */ if(r <= 10) { - LogPrintf("CDarkSendPool::ChargeRandomFees -- charging random fees. %u\n", i); + LogPrintf("CDarksendPool::ChargeRandomFees -- charging random fees. %u\n", i); CWalletTx wtxCollateral = CWalletTx(pwalletMain, txCollateral); @@ -847,7 +981,7 @@ void CDarkSendPool::ChargeRandomFees(){ if (!wtxCollateral.AcceptToMemoryPool(true)) { // This must not fail. The transaction has already been signed and recorded. - LogPrintf("CDarkSendPool::ChargeRandomFees() : Error: Transaction not valid"); + LogPrintf("CDarksendPool::ChargeRandomFees() : Error: Transaction not valid"); } wtxCollateral.RelayWalletTransaction(); } @@ -858,13 +992,13 @@ void CDarkSendPool::ChargeRandomFees(){ // // Check for various timeouts (queue objects, darksend, etc) // -void CDarkSendPool::CheckTimeout(){ +void CDarksendPool::CheckTimeout(){ if(!fEnableDarksend && !fMasterNode) return; // catching hanging sessions if(!fMasterNode) { if(state == POOL_STATUS_TRANSMISSION) { - if(fDebug) LogPrintf("CDarkSendPool::CheckTimeout() -- Session complete -- Running Check()\n"); + if(fDebug) LogPrintf("CDarksendPool::CheckTimeout() -- Session complete -- Running Check()\n"); Check(); } } @@ -874,26 +1008,13 @@ void CDarkSendPool::CheckTimeout(){ vector::iterator it; for(it=vecDarksendQueue.begin();it::iterator it2; for(it2=vec->begin();it2end();it2++){ if((*it2).IsExpired()){ - if(fDebug) LogPrintf("CDarkSendPool::CheckTimeout() : Removing expired entry - %d\n", c); + if(fDebug) LogPrintf("CDarksendPool::CheckTimeout() : Removing expired entry - %d\n", c); vec->erase(it2); if(entries.size() == 0 && myEntries.size() == 0){ SetNull(true); UnlockCoins(); } if(fMasterNode){ - RelayDarkSendStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET); + RelayStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET); } break; } c++; } + if(!fSubmitAnonymousFailed && !fMasterNode && state == POOL_STATUS_ACCEPTING_ENTRIES){ + if(GetTimeMillis()-lastTimeChanged >= (DARKSEND_DOWNGRADE_TIMEOUT*1000)+addLagTime){ + lastTimeChanged = GetTimeMillis(); + Downgrade(); + } + } + if(GetTimeMillis()-lastTimeChanged >= (DARKSEND_QUEUE_TIMEOUT*1000)+addLagTime){ lastTimeChanged = GetTimeMillis(); @@ -935,7 +1063,7 @@ void CDarkSendPool::CheckTimeout(){ UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); } } else if(GetTimeMillis()-lastTimeChanged >= (DARKSEND_QUEUE_TIMEOUT*1000)+addLagTime){ - if(fDebug) LogPrintf("CDarkSendPool::CheckTimeout() -- Session timed out (30s) -- resetting\n"); + if(fDebug) LogPrintf("CDarksendPool::CheckTimeout() -- Session timed out (30s) -- resetting\n"); SetNull(); UnlockCoins(); @@ -944,19 +1072,52 @@ void CDarkSendPool::CheckTimeout(){ } if(state == POOL_STATUS_SIGNING && GetTimeMillis()-lastTimeChanged >= (DARKSEND_SIGNING_TIMEOUT*1000)+addLagTime ) { - if(fDebug) LogPrintf("CDarkSendPool::CheckTimeout() -- Session timed out -- restting\n"); - ChargeFees(); - SetNull(); - UnlockCoins(); - //add my transactions to the new session + if(fSubmitAnonymousFailed){ + if(fDebug) LogPrintf("CDarksendPool::CheckTimeout() -- Session timed out -- restting\n"); + ChargeFees(); + SetNull(); + UnlockCoins(); + //add my transactions to the new session - UpdateState(POOL_STATUS_ERROR); - lastMessage = _("Signing timed out, please resubmit."); + UpdateState(POOL_STATUS_ERROR); + lastMessage = _("Signing timed out, please resubmit."); + } else { //Downgrade and try again + Downgrade(); + finalTransaction.vin.clear(); + finalTransaction.vout.clear(); + UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); + lastMessage = _("Downgrading and trying again."); + } + } +} + +// +// Check for complete queue +// +void CDarksendPool::CheckForCompleteQueue(){ + if(!fEnableDarksend && !fMasterNode) return; + + /* Check to see if we're ready for submissions from clients */ + // + // After receiving multiple dsa messages, the queue will switch to "accepting entries" + // which is the active state right before merging the transaction + // + if(state == POOL_STATUS_QUEUE && sessionUsers == GetMaxPoolTransactions()) { + printf("Q ready"); + UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); + + CDarksendQueue dsq; + dsq.nDenom = sessionDenom; + dsq.vin = activeMasternode.vin; + dsq.time = GetTime(); + dsq.ready = true; + dsq.Sign(); + dsq.Relay(); } } // check to see if the signature is valid -bool CDarkSendPool::SignatureValid(const CScript& newSig, const CTxIn& newVin){ +bool CDarksendPool::SignatureValid(const CScript& newSig, const CTxIn& newVin){ CTransaction txNew; txNew.vin.clear(); txNew.vout.clear(); @@ -965,16 +1126,16 @@ bool CDarkSendPool::SignatureValid(const CScript& newSig, const CTxIn& newVin){ CScript sigPubKey = CScript(); unsigned int i = 0; - BOOST_FOREACH(CDarkSendEntry e, entries) { - BOOST_FOREACH(const CTxOut out, e.vout) + BOOST_FOREACH(CDarkSendEntry& e, entries) { + BOOST_FOREACH(const CTxOut& out, e.vout) txNew.vout.push_back(out); - BOOST_FOREACH(const CDarkSendEntryVin s, e.sev){ - txNew.vin.push_back(s.vin); + BOOST_FOREACH(const CTxDSIn& s, e.sev){ + txNew.vin.push_back(s); - if(s.vin == newVin){ + if(s == newVin){ found = i; - sigPubKey = s.vin.prevPubKey; + sigPubKey = s.prevPubKey; } i++; } @@ -983,19 +1144,19 @@ bool CDarkSendPool::SignatureValid(const CScript& newSig, const CTxIn& newVin){ if(found >= 0){ //might have to do this one input at a time? int n = found; txNew.vin[n].scriptSig = newSig; - if(fDebug) LogPrintf("CDarkSendPool::SignatureValid() - Sign with sig %s\n", newSig.ToString().substr(0,24).c_str()); + if(fDebug) LogPrintf("CDarksendPool::SignatureValid() - Sign with sig %s\n", newSig.ToString().substr(0,24).c_str()); if (!VerifyScript(txNew.vin[n].scriptSig, sigPubKey, txNew, n, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, 0)){ - if(fDebug) LogPrintf("CDarkSendPool::SignatureValid() - Signing - Error signing input %u\n", n); + if(fDebug) LogPrintf("CDarksendPool::SignatureValid() - Signing - Error signing input %u\n", n); return false; } } - if(fDebug) LogPrintf("CDarkSendPool::SignatureValid() - Signing - Successfully signed input\n"); + if(fDebug) LogPrintf("CDarksendPool::SignatureValid() - Signing - Successfully validated input\n"); return true; } // check to make sure the collateral provided by the client is valid -bool CDarkSendPool::IsCollateralValid(const CTransaction& txCollateral){ +bool CDarksendPool::IsCollateralValid(const CTransaction& txCollateral){ if(txCollateral.vout.size() < 1) return false; if(txCollateral.nLockTime != 0) return false; @@ -1007,7 +1168,7 @@ bool CDarkSendPool::IsCollateralValid(const CTransaction& txCollateral){ nValueOut += o.nValue; if(!o.scriptPubKey.IsNormalPaymentScript()){ - LogPrintf ("CDarkSendPool::IsCollateralValid - Invalid Script %s\n", txCollateral.ToString().c_str()); + LogPrintf ("CDarksendPool::IsCollateralValid - Invalid Script %s\n", txCollateral.ToString().c_str()); return false; } } @@ -1025,21 +1186,21 @@ bool CDarkSendPool::IsCollateralValid(const CTransaction& txCollateral){ } if(missingTx){ - if(fDebug) LogPrintf ("CDarkSendPool::IsCollateralValid - Unknown inputs in collateral transaction - %s\n", txCollateral.ToString().c_str()); + if(fDebug) LogPrintf ("CDarksendPool::IsCollateralValid - Unknown inputs in collateral transaction - %s\n", txCollateral.ToString().c_str()); return false; } //collateral transactions are required to pay out DARKSEND_COLLATERAL as a fee to the miners if(nValueIn - nValueOut < DARKSEND_COLLATERAL) { - if(fDebug) LogPrintf ("CDarkSendPool::IsCollateralValid - did not include enough fees in transaction %d\n%s\n", nValueOut-nValueIn, txCollateral.ToString().c_str()); + if(fDebug) LogPrintf ("CDarksendPool::IsCollateralValid - did not include enough fees in transaction %d\n%s\n", nValueOut-nValueIn, txCollateral.ToString().c_str()); return false; } - if(fDebug) LogPrintf("CDarkSendPool::IsCollateralValid %s\n", txCollateral.ToString().c_str()); + if(fDebug) LogPrintf("CDarksendPool::IsCollateralValid %s\n", txCollateral.ToString().c_str()); CValidationState state; if(!AcceptableInputs(mempool, state, txCollateral)){ - if(fDebug) LogPrintf ("CDarkSendPool::IsCollateralValid - didn't pass IsAcceptable\n"); + if(fDebug) LogPrintf ("CDarksendPool::IsCollateralValid - didn't pass IsAcceptable\n"); return false; } @@ -1050,12 +1211,12 @@ bool CDarkSendPool::IsCollateralValid(const CTransaction& txCollateral){ // // Add a clients transaction to the pool // -bool CDarkSendPool::AddEntry(const std::vector& newInput, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector& newOutput, std::string& error){ +bool CDarksendPool::AddEntry(const std::vector& newInput, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector& newOutput, std::string& error){ if (!fMasterNode) return false; BOOST_FOREACH(CTxIn in, newInput) { if (in.prevout.IsNull() || nAmount < 0) { - if(fDebug) LogPrintf ("CDarkSendPool::AddEntry - input not valid!\n"); + if(fDebug) LogPrintf ("CDarksendPool::AddEntry - input not valid!\n"); error = _("Input is not valid."); sessionUsers--; return false; @@ -1063,14 +1224,14 @@ bool CDarkSendPool::AddEntry(const std::vector& newInput, const int64_t& } if (!IsCollateralValid(txCollateral)){ - if(fDebug) LogPrintf ("CDarkSendPool::AddEntry - collateral not valid!\n"); + if(fDebug) LogPrintf ("CDarksendPool::AddEntry - collateral not valid!\n"); error = _("Collateral is not valid."); sessionUsers--; return false; } if((int)entries.size() >= GetMaxPoolTransactions()){ - if(fDebug) LogPrintf ("CDarkSendPool::AddEntry - entries is full!\n"); + if(fDebug) LogPrintf ("CDarksendPool::AddEntry - entries is full!\n"); error = _("Entries are full."); sessionUsers--; return false; @@ -1078,10 +1239,10 @@ bool CDarkSendPool::AddEntry(const std::vector& newInput, const int64_t& BOOST_FOREACH(CTxIn in, newInput) { if(fDebug) LogPrintf("looking for vin -- %s\n", in.ToString().c_str()); - BOOST_FOREACH(const CDarkSendEntry v, entries) { - BOOST_FOREACH(const CDarkSendEntryVin s, v.sev){ - if(s.vin == in) { - if(fDebug) LogPrintf ("CDarkSendPool::AddEntry - found in vin\n"); + BOOST_FOREACH(const CDarkSendEntry& v, entries) { + BOOST_FOREACH(const CTxDSIn& s, v.sev){ + if((CTxIn)s == in) { + if(fDebug) LogPrintf ("CDarksendPool::AddEntry - found in vin\n"); error = _("Already have that input."); sessionUsers--; return false; @@ -1090,67 +1251,61 @@ bool CDarkSendPool::AddEntry(const std::vector& newInput, const int64_t& } } - if(state == POOL_STATUS_ACCEPTING_ENTRIES) { - CDarkSendEntry v; - v.Add(newInput, nAmount, txCollateral, newOutput); - entries.push_back(v); + CDarkSendEntry v; + v.Add(newInput, nAmount, txCollateral, newOutput); + entries.push_back(v); - if(fDebug) LogPrintf("CDarkSendPool::AddEntry -- adding %s\n", newInput[0].ToString().c_str()); - error = ""; + if(fDebug) LogPrintf("CDarksendPool::AddEntry -- adding %s\n", newInput[0].ToString().c_str()); + error = ""; - return true; - } - - if(fDebug) LogPrintf ("CDarkSendPool::AddEntry - can't accept new entry, wrong state!\n"); - error = _("Wrong state."); - sessionUsers--; - return false; + return true; } -bool CDarkSendPool::AddScriptSig(const CTxIn& newVin){ - if(fDebug) LogPrintf("CDarkSendPool::AddScriptSig -- new sig %s\n", newVin.scriptSig.ToString().substr(0,24).c_str()); +bool CDarksendPool::AddScriptSig(const CTxIn& newVin){ + if(fDebug) LogPrintf("CDarksendPool::AddScriptSig -- new sig %s\n", newVin.scriptSig.ToString().substr(0,24).c_str()); - BOOST_FOREACH(const CDarkSendEntry v, entries) { - BOOST_FOREACH(const CDarkSendEntryVin s, v.sev){ - if(s.vin.scriptSig == newVin.scriptSig) { - LogPrintf("CDarkSendPool::AddScriptSig - already exists \n"); + + BOOST_FOREACH(const CDarkSendEntry& v, entries) { + BOOST_FOREACH(const CTxDSIn& s, v.sev){ + if(s.scriptSig == newVin.scriptSig) { + LogPrintf("CDarksendPool::AddScriptSig - already exists \n"); return false; } } } if(!SignatureValid(newVin.scriptSig, newVin)){ - if(fDebug) LogPrintf("CDarkSendPool::AddScriptSig - Invalid Sig\n"); + if(fDebug) LogPrintf("CDarksendPool::AddScriptSig - Invalid Sig\n"); return false; } - if(fDebug) LogPrintf("CDarkSendPool::AddScriptSig -- sig %s\n", newVin.ToString().c_str()); + if(fDebug) LogPrintf("CDarksendPool::AddScriptSig -- sig %s\n", newVin.ToString().c_str()); - if(state == POOL_STATUS_SIGNING) { - BOOST_FOREACH(CTxIn& vin, finalTransaction.vin){ - if(newVin.prevout == vin.prevout && vin.nSequence == newVin.nSequence){ - vin.scriptSig = newVin.scriptSig; - vin.prevPubKey = newVin.prevPubKey; - if(fDebug) LogPrintf("CDarkSendPool::AddScriptSig -- adding to finalTransaction %s\n", newVin.scriptSig.ToString().substr(0,24).c_str()); - } - } - for(unsigned int i = 0; i < entries.size(); i++){ - if(entries[i].AddSig(newVin)){ - if(fDebug) LogPrintf("CDarkSendPool::AddScriptSig -- adding %s\n", newVin.scriptSig.ToString().substr(0,24).c_str()); - return true; - } + BOOST_FOREACH(CTxIn& vin, finalTransaction.vin){ + if(newVin.prevout == vin.prevout && vin.nSequence == newVin.nSequence){ + vin.scriptSig = newVin.scriptSig; + vin.prevPubKey = newVin.prevPubKey; + if(fDebug) LogPrintf("CDarksendPool::AddScriptSig -- adding to finalTransaction %s\n", newVin.scriptSig.ToString().substr(0,24).c_str()); + return true; } } - LogPrintf("CDarkSendPool::AddScriptSig -- Couldn't set sig!\n" ); + LogPrintf("CDarksendPool::AddScriptSig -- Couldn't set sig!\n" ); return false; } // check to make sure everything is signed -bool CDarkSendPool::SignaturesComplete(){ - BOOST_FOREACH(const CDarkSendEntry v, entries) { - BOOST_FOREACH(const CDarkSendEntryVin s, v.sev){ - if(!s.isSigSet) return false; +bool CDarksendPool::SignaturesComplete(){ + bool fFoundIncomplete = false; + BOOST_FOREACH(CTxDSIn in, anonTx.vin){ + if(!in.fHasSig) + fFoundIncomplete = true; + } + if(fFoundIncomplete == false) return true; + + BOOST_FOREACH(const CDarkSendEntry& v, entries) { + BOOST_FOREACH(const CTxDSIn& s, v.sev){ + if(!s.fHasSig) return false; } } return true; @@ -1160,7 +1315,7 @@ bool CDarkSendPool::SignaturesComplete(){ // Execute a darksend denomination via a masternode. // This is only ran from clients // -void CDarkSendPool::SendDarksendDenominate(std::vector& vin, std::vector& vout, int64_t amount){ +void CDarksendPool::SendDarksendDenominate(std::vector& vin, std::vector& vout, int64_t amount){ if(darkSendPool.txCollateral == CTransaction()){ LogPrintf ("CDarksendPool:SendDarksendDenominate() - Darksend collateral not set"); return; @@ -1179,7 +1334,7 @@ void CDarkSendPool::SendDarksendDenominate(std::vector& vin, std::vector< // we should already be connected to a masternode if(!sessionFoundMasternode){ - LogPrintf("CDarkSendPool::SendDarksendDenominate() - No masternode has been selected yet.\n"); + LogPrintf("CDarksendPool::SendDarksendDenominate() - No masternode has been selected yet.\n"); UnlockCoins(); SetNull(true); return; @@ -1189,13 +1344,13 @@ void CDarkSendPool::SendDarksendDenominate(std::vector& vin, std::vector< return; if(fMasterNode) { - LogPrintf("CDarkSendPool::SendDarksendDenominate() - DarkSend from a masternode is not supported currently.\n"); + LogPrintf("CDarksendPool::SendDarksendDenominate() - DarkSend from a masternode is not supported currently.\n"); return; } UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); - LogPrintf("CDarkSendPool::SendDarksendDenominate() - Added transaction to pool.\n"); + LogPrintf("CDarksendPool::SendDarksendDenominate() - Added transaction to pool.\n"); ClearLastMessage(); @@ -1206,17 +1361,19 @@ void CDarkSendPool::SendDarksendDenominate(std::vector& vin, std::vector< CValidationState state; CTransaction tx; - BOOST_FOREACH(const CTxOut o, vout){ + BOOST_FOREACH(const CTxOut& o, vout){ nValueOut += o.nValue; tx.vout.push_back(o); } - BOOST_FOREACH(const CTxIn i, vin){ + BOOST_FOREACH(const CTxIn& i, vin){ tx.vin.push_back(i); if(fDebug) LogPrintf("dsi -- tx in %s\n", i.ToString().c_str()); } + printf("Submitting tx %s\n", tx.ToString().c_str()); + if(!AcceptableInputs(mempool, state, tx)){ LogPrintf("dsi -- transaction not valid! %s \n", tx.ToString().c_str()); return; @@ -1228,8 +1385,9 @@ void CDarkSendPool::SendDarksendDenominate(std::vector& vin, std::vector< e.Add(vin, amount, txCollateral, vout); myEntries.push_back(e); - // relay our entry to the master node - RelayDarkSendIn(vin, amount, txCollateral, vout); + // submit inputs/outputs through relays + RelayInAnon(vin, vout); + Check(); } @@ -1238,7 +1396,7 @@ void CDarkSendPool::SendDarksendDenominate(std::vector& vin, std::vector< // 0 means transaction was not accepted // 1 means transaction was accepted -bool CDarkSendPool::StatusUpdate(int newState, int newEntriesCount, int newAccepted, std::string& error, int newSessionID){ +bool CDarksendPool::StatusUpdate(int newState, int newEntriesCount, int newAccepted, std::string& error, int newSessionID){ if(fMasterNode) return false; if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) return false; @@ -1257,19 +1415,20 @@ bool CDarkSendPool::StatusUpdate(int newState, int newEntriesCount, int newAccep if(newAccepted == 1) { sessionID = newSessionID; - LogPrintf("CDarkSendPool::StatusUpdate - set sessionID to %d\n", sessionID); + LogPrintf("CDarksendPool::StatusUpdate - set sessionID to %d\n", sessionID); sessionFoundMasternode = true; } } if(newState == POOL_STATUS_ACCEPTING_ENTRIES){ if(newAccepted == 1){ - LogPrintf("CDarkSendPool::StatusUpdate - entry accepted! \n"); + LogPrintf("CDarksendPool::StatusUpdate - entry accepted! \n"); sessionFoundMasternode = true; //wait for other users. Masternode will report when ready UpdateState(POOL_STATUS_QUEUE); + printf("Updated 1\n"); } else if (newAccepted == 0 && sessionID == 0 && !sessionFoundMasternode) { - LogPrintf("CDarkSendPool::StatusUpdate - entry not accepted by masternode \n"); + LogPrintf("CDarksendPool::StatusUpdate - entry not accepted by masternode \n"); UnlockCoins(); UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); DoAutomaticDenominating(); //try another masternode @@ -1285,32 +1444,27 @@ bool CDarkSendPool::StatusUpdate(int newState, int newEntriesCount, int newAccep // check it to make sure it's what we want, then sign it if we agree. // If we refuse to sign, it's possible we'll be charged collateral // -bool CDarkSendPool::SignFinalTransaction(CTransaction& finalTransactionNew, CNode* node){ - if(fDebug) LogPrintf("CDarkSendPool::AddFinalTransaction - Got Finalized Transaction\n"); - - if(!finalTransaction.vin.empty()){ - LogPrintf("CDarkSendPool::AddFinalTransaction - Rejected Final Transaction!\n"); - return false; - } +bool CDarksendPool::SignFinalTransaction(CTransaction& finalTransactionNew, CNode* node){ + if(fDebug) LogPrintf("CDarksendPool::SignFinalTransaction - Got Finalized Transaction - fSubmitAnonymousFailed %d\n", fSubmitAnonymousFailed); finalTransaction = finalTransactionNew; - LogPrintf("CDarkSendPool::SignFinalTransaction %s\n", finalTransaction.ToString().c_str()); + LogPrintf("CDarksendPool::SignFinalTransaction %s\n", finalTransaction.ToString().c_str()); vector sigs; //make sure my inputs/outputs are present, otherwise refuse to sign BOOST_FOREACH(const CDarkSendEntry e, myEntries) { - BOOST_FOREACH(const CDarkSendEntryVin s, e.sev) { + BOOST_FOREACH(const CTxDSIn s, e.sev) { /* Sign my transaction and all outputs */ int mine = -1; CScript prevPubKey = CScript(); CTxIn vin = CTxIn(); for(unsigned int i = 0; i < finalTransaction.vin.size(); i++){ - if(finalTransaction.vin[i] == s.vin){ + if(finalTransaction.vin[i] == s){ mine = i; - prevPubKey = s.vin.prevPubKey; - vin = s.vin; + prevPubKey = s.prevPubKey; + vin = s; } } @@ -1320,7 +1474,7 @@ bool CDarkSendPool::SignFinalTransaction(CTransaction& finalTransactionNew, CNod int64_t nValue2 = 0; for(unsigned int i = 0; i < finalTransaction.vout.size(); i++){ - BOOST_FOREACH(const CTxOut o, e.vout) { + BOOST_FOREACH(const CTxOut& o, e.vout) { if(finalTransaction.vout[i] == o){ foundOutputs++; nValue1 += finalTransaction.vout[i].nValue; @@ -1335,13 +1489,14 @@ bool CDarkSendPool::SignFinalTransaction(CTransaction& finalTransactionNew, CNod if(foundOutputs < targetOuputs || 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 // better then signing if the transaction doesn't look like what we wanted. - LogPrintf("CDarkSendPool::Sign - My entries are not correct! Refusing to sign. %d entries %d target. \n", foundOutputs, targetOuputs); + LogPrintf("CDarksendPool::Sign - My entries are not correct! Refusing to sign. %d entries %d target. \n", foundOutputs, targetOuputs); + ResendMissingInputsOutputs(); return false; } - if(fDebug) LogPrintf("CDarkSendPool::Sign - Signing my input %i\n", mine); + if(fDebug) LogPrintf("CDarksendPool::Sign - Signing my input %i\n", mine); if(!SignSignature(*pwalletMain, prevPubKey, finalTransaction, mine, int(SIGHASH_ALL|SIGHASH_ANYONECANPAY))) { // changes scriptSig - if(fDebug) LogPrintf("CDarkSendPool::Sign - Unable to sign my own transaction! \n"); + if(fDebug) LogPrintf("CDarksendPool::Sign - Unable to sign my own transaction! \n"); // not sure what to do here, it will timeout...? } @@ -1351,19 +1506,23 @@ bool CDarkSendPool::SignFinalTransaction(CTransaction& finalTransactionNew, CNod } - if(fDebug) LogPrintf("CDarkSendPool::Sign - txNew:\n%s", finalTransaction.ToString().c_str()); + if(fDebug) LogPrintf("CDarksendPool::Sign - txNew:\n%s", finalTransaction.ToString().c_str()); } - // push all of our signatures to the masternode - if(sigs.size() > 0 && node != NULL) - node->PushMessage("dss", sigs); + if(!fSubmitAnonymousFailed){ + RelaySignaturesAnon(sigs); + } else { + // push all of our signatures to the masternode + if(sigs.size() > 0 && node != NULL) + node->PushMessage("dss", sigs); + } return true; } -void CDarkSendPool::NewBlock() +void CDarksendPool::NewBlock() { - if(fDebug) LogPrintf("CDarkSendPool::NewBlock \n"); + if(fDebug) LogPrintf("CDarksendPool::NewBlock \n"); //we we're processing lots of blocks, we'll just leave if(GetTime() - lastNewBlock < 10) return; @@ -1380,30 +1539,32 @@ void CDarkSendPool::NewBlock() } // Darksend transaction was completed (failed or successed) -void CDarkSendPool::CompletedTransaction(bool error, std::string lastMessageNew) +void CDarksendPool::CompletedTransaction(bool error, std::string lastMessageNew) { if(fMasterNode) return; if(error){ LogPrintf("CompletedTransaction -- error \n"); UpdateState(POOL_STATUS_ERROR); + + Check(); + UnlockCoins(); } else { LogPrintf("CompletedTransaction -- success \n"); UpdateState(POOL_STATUS_SUCCESS); myEntries.clear(); + UnlockCoins(); + if(!fMasterNode) SetNull(true); // To avoid race conditions, we'll only let DS run once per block cachedLastSuccess = chainActive.Tip()->nHeight; } lastMessage = lastMessageNew; - completedTransaction = true; - Check(); - UnlockCoins(); } -void CDarkSendPool::ClearLastMessage() +void CDarksendPool::ClearLastMessage() { lastMessage = ""; } @@ -1413,7 +1574,7 @@ void CDarkSendPool::ClearLastMessage() // // This does NOT run by default for daemons, only for QT. // -bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) +bool CDarksendPool::DoAutomaticDenominating(bool fDryRun, bool ready) { LOCK(cs_darksend); @@ -1423,12 +1584,12 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) if(state == POOL_STATUS_ERROR || state == POOL_STATUS_SUCCESS) return false; if(chainActive.Tip()->nHeight - cachedLastSuccess < minBlockSpacing) { - LogPrintf("CDarkSendPool::DoAutomaticDenominating - Last successful darksend action was too recent\n"); + LogPrintf("CDarksendPool::DoAutomaticDenominating - Last successful darksend action was too recent\n"); strAutoDenomResult = _("Last successful darksend action was too recent."); return false; } if(!fEnableDarksend) { - if(fDebug) LogPrintf("CDarkSendPool::DoAutomaticDenominating - Darksend is disabled\n"); + if(fDebug) LogPrintf("CDarksendPool::DoAutomaticDenominating - Darksend is disabled\n"); strAutoDenomResult = _("Darksend is disabled."); return false; } @@ -1445,7 +1606,7 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) } if(mnodeman.size() == 0){ - if(fDebug) LogPrintf("CDarkSendPool::DoAutomaticDenominating - No masternodes detected\n"); + if(fDebug) LogPrintf("CDarksendPool::DoAutomaticDenominating - No masternodes detected\n"); strAutoDenomResult = _("No masternodes detected."); return false; } @@ -1475,14 +1636,9 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) if(nBalanceNeedsAnonymized < nLowestDenom) { -// if(nBalanceNeedsAnonymized > nValueMin) -// nBalanceNeedsAnonymized = nLowestDenom; -// else -// { - LogPrintf("DoAutomaticDenominating : No funds detected in need of denominating \n"); - strAutoDenomResult = _("No funds detected in need of denominating."); - return false; -// } + LogPrintf("DoAutomaticDenominating : No funds detected in need of denominating \n"); + strAutoDenomResult = _("No funds detected in need of denominating."); + return false; } if (fDebug) LogPrintf("DoAutomaticDenominating : nLowestDenom=%d, nBalanceNeedsAnonymized=%d\n", nLowestDenom, nBalanceNeedsAnonymized); @@ -1513,6 +1669,8 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) if(fDryRun) return true; + std::vector vOut; + // initial phase, find a masternode if(!sessionFoundMasternode){ int nUseQueue = rand()%100; @@ -1564,12 +1722,9 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) // connect to masternode and submit the queue request if(ConnectNode((CAddress)addr, NULL, true)){ - - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) + CNode* pNode = FindNode(addr); + if(pNode) { - if((CNetAddr)pnode->addr != (CNetAddr)addr) continue; - std::string strReason; if(txCollateral == CTransaction()){ if(!pwalletMain->CreateCollateralTransaction(txCollateral, strReason)){ @@ -1578,12 +1733,12 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) } } - submittedToMasternode = addr; + pSubmittedToMasternode = mnodeman.Find(dsq.vin); vecMasternodesUsed.push_back(dsq.vin); sessionDenom = dsq.nDenom; - pnode->PushMessage("dsa", sessionDenom, txCollateral); - LogPrintf("DoAutomaticDenominating --- connected (from queue), sending dsa for %d %d - %s\n", sessionDenom, GetDenominationsByAmount(sessionTotalValue), pnode->addr.ToString().c_str()); + pNode->PushMessage("dsa", sessionDenom, txCollateral); + LogPrintf("DoAutomaticDenominating --- connected (from queue), sending dsa for %d %d - %s\n", sessionDenom, GetDenominationsByAmount(sessionTotalValue), pNode->addr.ToString().c_str()); strAutoDenomResult = ""; return true; } @@ -1643,7 +1798,7 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) } } - submittedToMasternode = pmn->addr; + pSubmittedToMasternode = pmn; vecMasternodesUsed.push_back(pmn->vin); std::vector vecAmounts; @@ -1674,7 +1829,7 @@ bool CDarkSendPool::DoAutomaticDenominating(bool fDryRun, bool ready) } -bool CDarkSendPool::PrepareDarksendDenominate() +bool CDarksendPool::PrepareDarksendDenominate() { // Submit transaction to the pool if we get here, use sessionDenom so we use the same amount of money std::string strError = pwalletMain->PrepareDarksendDenominate(0, nDarksendRounds); @@ -1687,7 +1842,35 @@ bool CDarkSendPool::PrepareDarksendDenominate() return false; } -bool CDarkSendPool::SendRandomPaymentToSelf() +bool CDarksendPool::Downgrade() +{ + if(fSubmitAnonymousFailed) return true; + if(myEntries.size() == 0) return false; + + fSubmitAnonymousFailed = true; + LogPrintf("CDarksendPool::Downgrade() : Downgrading and submitting directly\n"); + + // relay our entry to the master node + RelayIn(myEntries[0].sev, myEntries[0].amount, txCollateral, myEntries[0].vout); + + return true; +} + +bool CDarksendPool::ResendMissingInputsOutputs() +{ + if(fResentInputsOutputs) { + Downgrade(); + return true; + } + if(myEntries.size() == 0) return false; + + LogPrintf("CDarksendPool::Downgrade() : Downgrading and submitting directly\n"); + RelayInAnon(myEntries[0].sev, myEntries[0].vout); + fResentInputsOutputs = true; + return true; +} + +bool CDarksendPool::SendRandomPaymentToSelf() { int64_t nBalance = pwalletMain->GetBalance(); int64_t nPayment = (nBalance*0.35) + (rand() % nBalance); @@ -1725,7 +1908,7 @@ bool CDarkSendPool::SendRandomPaymentToSelf() } // Split up large inputs or create fee sized inputs -bool CDarkSendPool::MakeCollateralAmounts() +bool CDarksendPool::MakeCollateralAmounts() { // make our change address CReserveKey reservekey(pwalletMain); @@ -1767,7 +1950,7 @@ bool CDarkSendPool::MakeCollateralAmounts() } // Create denominations -bool CDarkSendPool::CreateDenominated(int64_t nTotalValue) +bool CDarksendPool::CreateDenominated(int64_t nTotalValue) { // make our change address CReserveKey reservekey(pwalletMain); @@ -1833,7 +2016,7 @@ bool CDarkSendPool::CreateDenominated(int64_t nTotalValue) return true; } -bool CDarkSendPool::IsCompatibleWithEntries(std::vector vout) +bool CDarksendPool::IsCompatibleWithEntries(std::vector& vout) { BOOST_FOREACH(const CDarkSendEntry v, entries) { LogPrintf(" IsCompatibleWithEntries %d %d\n", GetDenominations(vout), GetDenominations(v.vout)); @@ -1850,12 +2033,12 @@ bool CDarkSendPool::IsCompatibleWithEntries(std::vector vout) return true; } -bool CDarkSendPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txCollateral, std::string& strReason) +bool CDarksendPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txCollateral, std::string& strReason) { - LogPrintf("CDarkSendPool::IsCompatibleWithSession - sessionDenom %d sessionUsers %d\n", sessionDenom, sessionUsers); + LogPrintf("CDarksendPool::IsCompatibleWithSession - sessionDenom %d sessionUsers %d\n", sessionDenom, sessionUsers); if (!unitTest && !IsCollateralValid(txCollateral)){ - if(fDebug) LogPrintf ("CDarkSendPool::IsCompatibleWithSession - collateral not valid!\n"); + if(fDebug) LogPrintf ("CDarksendPool::IsCompatibleWithSession - collateral not valid!\n"); strReason = _("Collateral not valid."); return false; } @@ -1869,7 +2052,7 @@ bool CDarkSendPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txColla entries.clear(); if(!unitTest){ - //broadcast that I'm accepting entries, only if it's the first entry though + //broadcast that I'm accepting entries, only if it's the first entry through CDarksendQueue dsq; dsq.nDenom = nDenom; dsq.vin = activeMasternode.vin; @@ -1879,14 +2062,15 @@ bool CDarkSendPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txColla } UpdateState(POOL_STATUS_QUEUE); + printf("Updated 2\n"); vecSessionCollateral.push_back(txCollateral); return true; } - if((state != POOL_STATUS_ACCEPTING_ENTRIES && state != POOL_STATUS_QUEUE) || sessionUsers >= GetMaxPoolTransactions()){ - if((state != POOL_STATUS_ACCEPTING_ENTRIES && state != POOL_STATUS_QUEUE)) strReason = _("Incompatible mode."); + if((state != POOL_STATUS_IDLE && state != POOL_STATUS_QUEUE) || sessionUsers >= GetMaxPoolTransactions()){ + if((state != POOL_STATUS_IDLE && state != POOL_STATUS_QUEUE)) strReason = _("Incompatible mode."); if(sessionUsers >= GetMaxPoolTransactions()) strReason = _("Masternode queue is full."); - LogPrintf("CDarkSendPool::IsCompatibleWithSession - incompatible mode, return false %d %d\n", state != POOL_STATUS_ACCEPTING_ENTRIES, sessionUsers >= GetMaxPoolTransactions()); + LogPrintf("CDarksendPool::IsCompatibleWithSession - incompatible mode, return false %d %d\n", state != POOL_STATUS_ACCEPTING_ENTRIES, sessionUsers >= GetMaxPoolTransactions()); return false; } @@ -1895,7 +2079,12 @@ bool CDarkSendPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txColla return false; } - LogPrintf("CDarkSendPool::IsCompatibleWithSession - compatible\n"); + if(state == POOL_STATUS_IDLE){ + LogPrintf("CDarksendPool::IsCompatibleWithSession - Pool is open to new entries\n"); + UpdateState(POOL_STATUS_ACCEPTING_ENTRIES); + } + + LogPrintf("CDarksendPool::IsCompatibleWithSession - compatible\n"); sessionUsers++; lastTimeChanged = GetTimeMillis(); @@ -1905,7 +2094,7 @@ bool CDarkSendPool::IsCompatibleWithSession(int64_t nDenom, CTransaction txColla } //create a nice string to show the denominations -void CDarkSendPool::GetDenominationsToString(int nDenom, std::string& strDenom){ +void CDarksendPool::GetDenominationsToString(int nDenom, std::string& strDenom){ // Function returns as follows: // // bit 0 - 100DRK+1 ( bit on if present ) @@ -1939,7 +2128,7 @@ void CDarkSendPool::GetDenominationsToString(int nDenom, std::string& strDenom){ } // return a bitshifted integer representing the denominations in this list -int CDarkSendPool::GetDenominations(const std::vector& vout){ +int CDarksendPool::GetDenominations(const std::vector& vout){ std::vector > denomUsed; // make a list of denominations, with zero uses @@ -1976,7 +2165,7 @@ int CDarkSendPool::GetDenominations(const std::vector& vout){ } -int CDarkSendPool::GetDenominationsByAmounts(std::vector& vecAmount){ +int CDarksendPool::GetDenominationsByAmounts(std::vector& vecAmount){ CScript e = CScript(); std::vector vout1; @@ -1992,7 +2181,7 @@ int CDarkSendPool::GetDenominationsByAmounts(std::vector& vecAmount){ return GetDenominations(vout1); } -int CDarkSendPool::GetDenominationsByAmount(int64_t nAmount, int nDenomTarget){ +int CDarksendPool::GetDenominationsByAmount(int64_t nAmount, int nDenomTarget){ CScript e = CScript(); int64_t nValueLeft = nAmount; @@ -2120,6 +2309,26 @@ bool CDarksendQueue::Sign() return false; } + // -- second signature, for proving access to the anonymous relay system + + nBlockHeight = chainActive.Tip()->nHeight; //sign with our current blockheight + strMessage = boost::lexical_cast(nBlockHeight); + + CKey secret; + secret.MakeNewKey(false); + strSharedKey = CBitcoinSecret(secret).ToString(); + + if(!darkSendSigner.SignMessage(strMessage, errorMessage, vchRelaySig, key2)) { + LogPrintf("CDarksendQueue():Relay - Sign message failed"); + return false; + } + + if(!darkSendSigner.VerifyMessage(pubkey2, vchRelaySig, strMessage, errorMessage)) { + LogPrintf("CDarksendQueue():Relay - Verify message failed"); + return false; + } + + return true; } @@ -2148,6 +2357,18 @@ bool CDarksendQueue::CheckSignature() return error("CDarksendQueue::CheckSignature() - Got bad masternode address signature %s \n", vin.ToString().c_str()); } + // -- second signature, for proving access to the anonymous relay system + + if(ready) + { + strMessage = boost::lexical_cast(nBlockHeight); + + if(!darkSendSigner.VerifyMessage(pmn->pubkey2, vchRelaySig, strMessage, errorMessage)) { + LogPrintf("CDarksendQueue():CheckSignature - Verify message failed"); + return false; + } + } + return true; } @@ -2155,6 +2376,111 @@ bool CDarksendQueue::CheckSignature() } +void CDarksendPool::RelayFinalTransaction(const int sessionID, const CTransaction& txNew) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + { + pnode->PushMessage("dsf", sessionID, txNew); + } +} + +void CDarksendPool::RelaySignaturesAnon(std::vector& vin) +{ + //empty + CTxOut out; + + BOOST_FOREACH(CTxIn& in, vin){ + LogPrintf("RelaySignaturesAnon - sig %s\n", in.ToString().c_str()); + CDarkSendRelay dsr(pSubmittedToMasternode->vin, vchMasternodeRelaySig, nMasternodeBlockHeight, DARKSEND_RELAY_SIG, in, out, strMasternodeSharedKey); + dsr.Relay(); + } +} + +void CDarksendPool::RelayInAnon(std::vector& vin, std::vector& vout) +{ + //empty in/out + CTxOut out; + CTxIn in; + + BOOST_FOREACH(CTxIn& in, vin){ + LogPrintf("RelayInAnon - in %s\n", in.ToString().c_str()); + CDarkSendRelay dsr(pSubmittedToMasternode->vin, vchMasternodeRelaySig, nMasternodeBlockHeight, DARKSEND_RELAY_IN, in, out, strMasternodeSharedKey); + dsr.Relay(); + } + + BOOST_FOREACH(CTxOut& out, vout){ + LogPrintf("RelayInAnon - out %s\n", out.ToString().c_str()); + CDarkSendRelay dsr(pSubmittedToMasternode->vin, vchMasternodeRelaySig, nMasternodeBlockHeight, DARKSEND_RELAY_OUT, in, out, strMasternodeSharedKey); + dsr.Relay(); + } +} + +void CDarksendPool::RelayIn(const std::vector& vin, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector& vout) +{ + LOCK(cs_vNodes); + + BOOST_FOREACH(CNode* pnode, vNodes) + { + if(!pSubmittedToMasternode) return; + if((CNetAddr)darkSendPool.pSubmittedToMasternode->addr != (CNetAddr)pnode->addr) continue; + LogPrintf("RelayIn - found master, relaying message - %s \n", pnode->addr.ToString().c_str()); + pnode->PushMessage("dsi", vin, nAmount, txCollateral, vout); + } +} + +void CDarksendPool::RelayStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const std::string error) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + pnode->PushMessage("dssu", sessionID, newState, newEntriesCount, newAccepted, error); +} + +void CDarksendPool::RelayCompletedTransaction(const int sessionID, const bool error, const std::string errorMessage) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + pnode->PushMessage("dsc", sessionID, error, errorMessage); +} + +bool CDSAnonTx::AddOutput(const CTxOut out){ + if(fDebug) LogPrintf("CDSAnonTx::AddOutput -- new %s\n", out.ToString().substr(0,24).c_str()); + + //already have this output + if(std::find(vout.begin(), vout.end(), out) != vout.end()) return false; + + vout.push_back(out); + std::random_shuffle ( vout.begin(), vout.end(), randomizeList); + + return true; +} + +bool CDSAnonTx::AddInput(const CTxIn in){ + if(fDebug) LogPrintf("CDSAnonTx::AddInput -- new %s\n", in.ToString().substr(0,24).c_str()); + + //already have this input + if(std::find(vin.begin(), vin.end(), in) != vin.end()) return false; + + vin.push_back(in); + + return true; +} + +bool CDSAnonTx::AddSig(const CTxIn newIn){ + if(fDebug) LogPrintf("CDSAnonTx::AddSig -- new %s\n", newIn.ToString().substr(0,24).c_str()); + + BOOST_FOREACH(CTxDSIn& in, vin){ + if(newIn.prevout == in.prevout && in.nSequence == newIn.nSequence){ + in.scriptSig = newIn.scriptSig; + in.prevPubKey = newIn.prevPubKey; + in.fHasSig = true; + return true; + } + } + + return false; +} + //TODO: Rename/move to core void ThreadCheckDarkSendPool() { @@ -2172,7 +2498,10 @@ void ThreadCheckDarkSendPool() MilliSleep(1000); //LogPrintf("ThreadCheckDarkSendPool::check timeout\n"); + + if(c % 10 == 0) darkSendPool.Check(); darkSendPool.CheckTimeout(); + darkSendPool.CheckForCompleteQueue(); if(c % 60 == 0) { @@ -2183,7 +2512,7 @@ void ThreadCheckDarkSendPool() segfaults from this code without the cs_main lock. */ mnodeman.CheckAndRemove(); - darkSendPool.ProcessMasternodeConnections(); + mnodeman.ProcessMasternodeConnections(); masternodePayments.CleanPaymentList(); CleanTransactionLocksList(); } @@ -2243,3 +2572,6 @@ void ThreadCheckDarkSendPool() } } } + + + diff --git a/src/darksend.h b/src/darksend.h index 70a879fff0..a7b3a6d2eb 100644 --- a/src/darksend.h +++ b/src/darksend.h @@ -9,9 +9,10 @@ #include "main.h" #include "activemasternode.h" #include "masternodeman.h" +#include "darksend-relay.h" class CTxIn; -class CDarkSendPool; +class CDarksendPool; class CDarkSendSigner; class CMasterNodeVote; class CBitcoinAddress; @@ -19,7 +20,9 @@ class CDarksendQueue; class CDarksendBroadcastTx; class CActiveMasternode; +// pool states for mixing #define POOL_MAX_TRANSACTIONS 3 // wait for X transactions to merge and publish +#define POOL_MAX_TRANSACTIONS_TESTNET 2 // wait for X transactions to merge and publish #define POOL_STATUS_UNKNOWN 0 // waiting for update #define POOL_STATUS_IDLE 1 // waiting for update #define POOL_STATUS_QUEUE 2 // waiting in a queue @@ -37,43 +40,49 @@ class CActiveMasternode; #define DARKSEND_QUEUE_TIMEOUT 120 #define DARKSEND_SIGNING_TIMEOUT 30 +#define DARKSEND_DOWNGRADE_TIMEOUT 30 -static const int MIN_POOL_PEER_PROTO_VERSION = 70067; // minimum peer version accepted by DarkSendPool +// used for anonymous relaying of inputs/outputs/sigs +#define DARKSEND_RELAY_IN 1 +#define DARKSEND_RELAY_OUT 2 +#define DARKSEND_RELAY_SIG 3 -extern CDarkSendPool darkSendPool; +extern CDarksendPool darkSendPool; extern CDarkSendSigner darkSendSigner; extern std::vector vecDarksendQueue; extern std::string strMasterNodePrivKey; extern map mapDarksendBroadcastTxes; extern CActiveMasternode activeMasternode; -//specific messages for the Darksend protocol -void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); - // get the darksend chain depth for a given input int GetInputDarksendRounds(CTxIn in, int rounds=0); +// +// Holds an Darksend input +// -// An input in the darksend pool -class CDarkSendEntryVin +class CTxDSIn : public CTxIn { public: - bool isSigSet; - CTxIn vin; + bool fHasSig; - CDarkSendEntryVin() + CTxDSIn(const CTxIn& in) { - isSigSet = false; - vin = CTxIn(); + prevout = in.prevout; + scriptSig = in.scriptSig; + prevPubKey = in.prevPubKey; + nSequence = in.nSequence; } }; + // A clients transaction in the darksend pool +// -- holds the input/output mapping for each user in the pool class CDarkSendEntry { public: bool isSet; - std::vector sev; + std::vector sev; int64_t amount; CTransaction collateral; std::vector vout; @@ -91,11 +100,7 @@ public: { if(isSet){return false;} - BOOST_FOREACH(const CTxIn v, vinIn) { - CDarkSendEntryVin s = CDarkSendEntryVin(); - s.vin = v; - sev.push_back(s); - } + sev = vinIn; vout = voutIn; amount = amountIn; collateral = collateralIn; @@ -105,28 +110,13 @@ public: return true; } - bool AddSig(const CTxIn& vin) - { - BOOST_FOREACH(CDarkSendEntryVin& s, sev) { - if(s.vin.prevout == vin.prevout && s.vin.nSequence == vin.nSequence){ - if(s.isSigSet){return false;} - s.vin.scriptSig = vin.scriptSig; - s.vin.prevPubKey = vin.prevPubKey; - s.isSigSet = true; - - return true; - } - } - - return false; - } - bool IsExpired() { return (GetTime() - addedTime) > DARKSEND_QUEUE_TIMEOUT;// 120 seconds } }; + // // A currently inprogress darksend merge and denomination information // @@ -139,12 +129,20 @@ public: bool ready; //ready for submit std::vector vchSig; + //information used for the anonymous relay system + int nBlockHeight; + std::vector vchRelaySig; + std::string strSharedKey; + CDarksendQueue() { nDenom = 0; vin = CTxIn(); time = 0; vchSig.clear(); + vchRelaySig.clear(); + nBlockHeight = 0; + strSharedKey = ""; ready = false; } @@ -155,6 +153,12 @@ public: READWRITE(time); READWRITE(ready); READWRITE(vchSig); + + if(ready){ + READWRITE(vchRelaySig); + READWRITE(nBlockHeight); + READWRITE(strSharedKey); + } ) bool GetAddress(CService &addr) @@ -213,15 +217,29 @@ public: bool VerifyMessage(CPubKey pubkey, std::vector& vchSig, std::string strMessage, std::string& errorMessage); }; -class CDarksendSession +// +// Build a transaction anonymously +// +class CDSAnonTx { +public: + std::vector vin; + std::vector vout; + bool IsTransactionValid(); + bool AddOutput(const CTxOut out); + bool AddInput(const CTxIn in); + bool AddSig(const CTxIn in); + int CountEntries() {return (int)vin.size() + (int)vout.size();} }; +void ConnectToDarkSendMasterNodeWinner(); + + // // Used to keep track of current status of darksend pool // -class CDarkSendPool +class CDarksendPool { public: @@ -231,6 +249,10 @@ public: std::vector entries; // the finalized transaction ready for signing CTransaction finalTransaction; + // anonymous inputs/outputs + CDSAnonTx anonTx; + bool fSubmitAnonymousFailed; + int nCountAttempts; int64_t lastTimeChanged; int64_t lastAutoDenomination; @@ -250,7 +272,7 @@ public: std::string lastMessage; bool completedTransaction; bool unitTest; - CService submittedToMasternode; + CMasternode* pSubmittedToMasternode; int sessionID; int sessionDenom; //Users must submit an denom matching this @@ -269,10 +291,16 @@ public: //debugging data std::string strAutoDenomResult; + // used for securing the anonymous relay system + vector vchMasternodeRelaySig; + int nMasternodeBlockHeight; + std::string strMasternodeSharedKey; + bool fResentInputsOutputs; + //incremented whenever a DSQ comes through int64_t nDsqCount; - CDarkSendPool() + CDarksendPool() { /* DarkSend uses collateral addresses to trust parties entering the pool to behave themselves. If they don't it takes their money. */ @@ -284,11 +312,14 @@ public: minBlockSpacing = 1; nDsqCount = 0; lastNewBlock = 0; + strMasternodeSharedKey = ""; + fResentInputsOutputs = false; SetNull(); } - void ProcessMasternodeConnections(); + //specific messages for the Darksend protocol + void ProcessMessageDarksend(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); void InitCollateralAddress(){ std::string strAddress = ""; @@ -306,6 +337,9 @@ public: bool SetCollateralAddress(std::string strAddress); void Reset(); + bool Downgrade(); + bool ResendMissingInputsOutputs(); + void SetNull(bool clearEverything=false); void UnlockCoins(); @@ -347,15 +381,15 @@ public: void UpdateState(unsigned int newState) { if (fMasterNode && (newState == POOL_STATUS_ERROR || newState == POOL_STATUS_SUCCESS)){ - LogPrintf("CDarkSendPool::UpdateState() - Can't set state to ERROR or SUCCESS as a masternode. \n"); + LogPrintf("CDarksendPool::UpdateState() - Can't set state to ERROR or SUCCESS as a masternode. \n"); return; } - LogPrintf("CDarkSendPool::UpdateState() == %d | %d \n", state, newState); + LogPrintf("CDarksendPool::UpdateState() == %d | %d \n", state, newState); if(state != newState){ lastTimeChanged = GetTimeMillis(); if(fMasterNode) { - RelayDarkSendStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET); + RelayStatus(darkSendPool.sessionID, darkSendPool.GetState(), darkSendPool.GetEntriesCount(), MASTERNODE_RESET); } } state = newState; @@ -364,7 +398,7 @@ public: int GetMaxPoolTransactions() { //if we're on testnet, just use two transactions per merge - if(Params().NetworkID() == CChainParams::TESTNET || Params().NetworkID() == CChainParams::REGTEST) return 2; + if(Params().NetworkID() == CChainParams::TESTNET || Params().NetworkID() == CChainParams::REGTEST) return POOL_MAX_TRANSACTIONS_TESTNET; //use the production amount return POOL_MAX_TRANSACTIONS; @@ -376,7 +410,8 @@ public: } // Are these outputs compatible with other client in the pool? - bool IsCompatibleWithEntries(std::vector vout); + bool IsCompatibleWithEntries(std::vector& vout); + // Is this amount compatible with other client in the pool? bool IsCompatibleWithSession(int64_t nAmount, CTransaction txCollateral, std::string& strReason); @@ -384,20 +419,33 @@ public: bool DoAutomaticDenominating(bool fDryRun=false, bool ready=false); bool PrepareDarksendDenominate(); - // check for process in Darksend void Check(); + void CheckFinalTransaction(); // charge fees to bad actors void ChargeFees(); // rarely charge fees to pay miners void ChargeRandomFees(); void CheckTimeout(); + void CheckForCompleteQueue(); // check to make sure a signature matches an input in the pool bool SignatureValid(const CScript& newSig, const CTxIn& newVin); // if the collateral is valid given by a client bool IsCollateralValid(const CTransaction& txCollateral); // add a clients entry to the pool bool AddEntry(const std::vector& newInput, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector& newOutput, std::string& error); + + // add an anonymous output/inputs/sig + bool AddAnonymousOutput(const CTxOut& out) {return anonTx.AddOutput(out);} + bool AddAnonymousInput(const CTxIn& in) {return anonTx.AddInput(in);} + bool AddAnonymousSig(const CTxIn& in) {return anonTx.AddSig(in);} + bool AddRelaySignature(vector vchMasternodeRelaySigIn, int nMasternodeBlockHeightIn, std::string strSharedKey) { + vchMasternodeRelaySig = vchMasternodeRelaySigIn; + nMasternodeBlockHeight = nMasternodeBlockHeightIn; + strMasternodeSharedKey = strSharedKey; + return true; + } + // add signature to a vin bool AddScriptSig(const CTxIn& newVin); // are all inputs signed? @@ -418,21 +466,32 @@ public: void ClearLastMessage(); // used for liquidity providers bool SendRandomPaymentToSelf(); + // split up large inputs or make fee sized inputs bool MakeCollateralAmounts(); bool CreateDenominated(int64_t nTotalValue); + // get the denominations for a list of outputs (returns a bitshifted integer) int GetDenominations(const std::vector& vout); void GetDenominationsToString(int nDenom, std::string& strDenom); + // get the denominations for a specific amount of darkcoin. int GetDenominationsByAmount(int64_t nAmount, int nDenomTarget=0); - int GetDenominationsByAmounts(std::vector& vecAmount); + + + // + // Relay Darksend Messages + // + + void RelayFinalTransaction(const int sessionID, const CTransaction& txNew); + void RelaySignaturesAnon(std::vector& vin); + void RelayInAnon(std::vector& vin, std::vector& vout); + void RelayIn(const std::vector& vin, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector& vout); + void RelayStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const std::string error=""); + void RelayCompletedTransaction(const int sessionID, const bool error, const std::string errorMessage); }; - -void ConnectToDarkSendMasterNodeWinner(); - void ThreadCheckDarkSendPool(); #endif diff --git a/src/main.cpp b/src/main.cpp index fc579b6737..e1db93c734 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4061,9 +4061,8 @@ void static ProcessGetData(CNode* pfrom) if (!pushed && inv.type == MSG_MASTERNODE_WINNER) { if(mapSeenMasternodeVotes.count(inv.hash)){ CDataStream ss(SER_NETWORK, PROTOCOL_VERSION); - int a = 0; ss.reserve(1000); - ss << mapSeenMasternodeVotes[inv.hash] << a; + ss << mapSeenMasternodeVotes[inv.hash]; pfrom->PushMessage("mnw", ss); pushed = true; } @@ -4824,7 +4823,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) else { //probably one the extensions - ProcessMessageDarksend(pfrom, strCommand, vRecv); + darkSendPool.ProcessMessageDarksend(pfrom, strCommand, vRecv); mnodeman.ProcessMessage(pfrom, strCommand, vRecv); ProcessMessageMasternodePayments(pfrom, strCommand, vRecv); ProcessMessageInstantX(pfrom, strCommand, vRecv); diff --git a/src/masternodeman.cpp b/src/masternodeman.cpp index 4104a184aa..2ea99be716 100644 --- a/src/masternodeman.cpp +++ b/src/masternodeman.cpp @@ -353,7 +353,7 @@ int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, in sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly()); - unsigned int rank = 0; + int rank = 0; BOOST_FOREACH (PAIRTYPE(unsigned int, CTxIn)& s, vecMasternodeScores){ rank++; if(s.second == vin) { @@ -364,6 +364,71 @@ int CMasternodeMan::GetMasternodeRank(const CTxIn& vin, int64_t nBlockHeight, in return -1; } +CMasternode* CMasternodeMan::GetMasternodeByRank(int nRank, int64_t nBlockHeight, int minProtocol) +{ + std::vector > vecMasternodeScores; + + // scan for winner + BOOST_FOREACH(CMasternode& mn, vMasternodes) { + + mn.Check(); + + if(mn.protocolVersion < minProtocol) continue; + if(!mn.IsEnabled()) { + continue; + } + + uint256 n = mn.CalculateScore(1, nBlockHeight); + unsigned int n2 = 0; + memcpy(&n2, &n, sizeof(n2)); + + vecMasternodeScores.push_back(make_pair(n2, mn.vin)); + } + + sort(vecMasternodeScores.rbegin(), vecMasternodeScores.rend(), CompareValueOnly()); + + int rank = 0; + BOOST_FOREACH (PAIRTYPE(unsigned int, CTxIn)& s, vecMasternodeScores){ + rank++; + if(rank == nRank) { + return Find(s.second); + } + } + + return NULL; +} + +void CMasternodeMan::ProcessMasternodeConnections() +{ + LOCK(cs_vNodes); + + if(!darkSendPool.pSubmittedToMasternode) return; + + BOOST_FOREACH(CNode* pnode, vNodes) + { + if(darkSendPool.pSubmittedToMasternode->addr == pnode->addr) continue; + + if(pnode->fDarkSendMaster){ + LogPrintf("Closing masternode connection %s \n", pnode->addr.ToString().c_str()); + pnode->CloseSocketDisconnect(); + } + } +} + +void CMasternodeMan::RelayMasternodeEntry(const CTxIn vin, const CService addr, const std::vector vchSig, const int64_t nNow, const CPubKey pubkey, const CPubKey pubkey2, const int count, const int current, const int64_t lastUpdated, const int protocolVersion) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + pnode->PushMessage("dsee", vin, addr, vchSig, nNow, pubkey, pubkey2, count, current, lastUpdated, protocolVersion); +} + +void CMasternodeMan::RelayMasternodeEntryPing(const CTxIn vin, const std::vector vchSig, const int64_t nNow, const bool stop) +{ + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) + pnode->PushMessage("dseep", vin, vchSig, nNow, stop); +} + void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv) { @@ -457,7 +522,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData pmn->addr = addr; pmn->Check(); if(pmn->IsEnabled()) - RelayDarkSendElectionEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion); + mnodeman.RelayMasternodeEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion); } } @@ -523,7 +588,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData } if(count == -1 && !isLocal) - RelayDarkSendElectionEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion); + mnodeman.RelayMasternodeEntry(vin, addr, vchSig, sigTime, pubkey, pubkey2, count, current, lastUpdated, protocolVersion); } else { LogPrintf("dsee - Rejected masternode entry %s\n", addr.ToString().c_str()); @@ -588,7 +653,7 @@ void CMasternodeMan::ProcessMessage(CNode* pfrom, std::string& strCommand, CData pmn->Check(); if(!pmn->IsEnabled()) return; } - RelayDarkSendElectionEntryPing(vin, vchSig, sigTime, stop); + mnodeman.RelayMasternodeEntryPing(vin, vchSig, sigTime, stop); } } return; diff --git a/src/masternodeman.h b/src/masternodeman.h index 6025bba989..52923ca72a 100644 --- a/src/masternodeman.h +++ b/src/masternodeman.h @@ -107,14 +107,25 @@ public: std::vector GetFullMasternodeVector() { Check(); return vMasternodes; } int GetMasternodeRank(const CTxIn &vin, int64_t nBlockHeight, int minProtocol=0); + CMasternode* GetMasternodeByRank(int nRank, int64_t nBlockHeight, int minProtocol=0); void ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv); + void ProcessMasternodeConnections(); + // Return the number of (unique) masternodes int size() { return vMasternodes.size(); } std::string ToString(); + // + // Relay Masternode Messages + // + + void RelayMasternodeEntry(const CTxIn vin, const CService addr, const std::vector vchSig, const int64_t nNow, const CPubKey pubkey, const CPubKey pubkey2, const int count, const int current, const int64_t lastUpdated, const int protocolVersion); + void RelayMasternodeEntryPing(const CTxIn vin, const std::vector vchSig, const int64_t nNow, const bool stop); + + }; #endif diff --git a/src/net.cpp b/src/net.cpp index c8c36e0b15..ea4ecdd802 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1874,85 +1874,6 @@ void RelayTransactionLockReq(const CTransaction& tx, const uint256& hash, bool r } -void RelayDarkSendFinalTransaction(const int sessionID, const CTransaction& txNew) -{ - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - pnode->PushMessage("dsf", sessionID, txNew); - } -} - -void RelayDarkSendIn(const std::vector& in, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector& out) -{ - LOCK(cs_vNodes); - - BOOST_FOREACH(CNode* pnode, vNodes) - { - if((CNetAddr)darkSendPool.submittedToMasternode != (CNetAddr)pnode->addr) continue; - LogPrintf("RelayDarkSendIn - found master, relaying message - %s \n", pnode->addr.ToString().c_str()); - pnode->PushMessage("dsi", in, nAmount, txCollateral, out); - } -} - -void RelayDarkSendStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const std::string error) -{ - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - pnode->PushMessage("dssu", sessionID, newState, newEntriesCount, newAccepted, error); - } -} - -void RelayDarkSendElectionEntry(const CTxIn vin, const CService addr, const std::vector vchSig, const int64_t nNow, const CPubKey pubkey, const CPubKey pubkey2, const int count, const int current, const int64_t lastUpdated, const int protocolVersion) -{ - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - if(!pnode->fRelayTxes) continue; - - pnode->PushMessage("dsee", vin, addr, vchSig, nNow, pubkey, pubkey2, count, current, lastUpdated, protocolVersion); - } -} - -void SendDarkSendElectionEntry(const CTxIn vin, const CService addr, const std::vector vchSig, const int64_t nNow, const CPubKey pubkey, const CPubKey pubkey2, const int count, const int current, const int64_t lastUpdated, const int protocolVersion) -{ - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - pnode->PushMessage("dsee", vin, addr, vchSig, nNow, pubkey, pubkey2, count, current, lastUpdated, protocolVersion); - } -} - -void RelayDarkSendElectionEntryPing(const CTxIn vin, const std::vector vchSig, const int64_t nNow, const bool stop) -{ - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - if(!pnode->fRelayTxes) continue; - - pnode->PushMessage("dseep", vin, vchSig, nNow, stop); - } -} - -void SendDarkSendElectionEntryPing(const CTxIn vin, const std::vector vchSig, const int64_t nNow, const bool stop) -{ - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - pnode->PushMessage("dseep", vin, vchSig, nNow, stop); - } -} - -void RelayDarkSendCompletedTransaction(const int sessionID, const bool error, const std::string errorMessage) -{ - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - pnode->PushMessage("dsc", sessionID, error, errorMessage); - } -} - void CNode::RecordBytesRecv(uint64_t bytes) { LOCK(cs_totalBytesRecv); @@ -2103,3 +2024,4 @@ bool CAddrDB::Read(CAddrMan& addr) return true; } + diff --git a/src/net.h b/src/net.h index 80b9909e2c..5838c980f3 100644 --- a/src/net.h +++ b/src/net.h @@ -760,15 +760,6 @@ class CTransaction; void RelayTransaction(const CTransaction& tx, const uint256& hash); void RelayTransaction(const CTransaction& tx, const uint256& hash, const CDataStream& ss); void RelayTransactionLockReq(const CTransaction& tx, const uint256& hash, bool relayToAll=false); -void RelayDarkSendFinalTransaction(const int sessionID, const CTransaction& txNew); -void RelayDarkSendIn(const std::vector& in, const int64_t& nAmount, const CTransaction& txCollateral, const std::vector& out); -void RelayDarkSendStatus(const int sessionID, const int newState, const int newEntriesCount, const int newAccepted, const std::string error=""); -void RelayDarkSendElectionEntry(const CTxIn vin, const CService addr, const std::vector vchSig, const int64_t nNow, const CPubKey pubkey, const CPubKey pubkey2, const int count, const int current, const int64_t lastUpdated, const int protocolVersion); -void SendDarkSendElectionEntry(const CTxIn vin, const CService addr, const std::vector vchSig, const int64_t nNow, const CPubKey pubkey, const CPubKey pubkey2, const int count, const int current, const int64_t lastUpdated, const int protocolVersion); -void RelayDarkSendElectionEntryPing(const CTxIn vin, const std::vector vchSig, const int64_t nNow, const bool stop); -void SendDarkSendElectionEntryPing(const CTxIn vin, const std::vector vchSig, const int64_t nNow, const bool stop); -void RelayDarkSendCompletedTransaction(const int sessionID, const bool error, const std::string errorMessage); -void RelayDarkSendMasterNodeContestant(); /** Access to the (IP) address database (peers.dat) */ diff --git a/src/qt/coincontroldialog.cpp b/src/qt/coincontroldialog.cpp index 40f397ec39..260a760f2f 100755 --- a/src/qt/coincontroldialog.cpp +++ b/src/qt/coincontroldialog.cpp @@ -543,6 +543,9 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) // Fee int64_t nFee = nTransactionFee * (1 + (int64_t)nBytes / 1000); + // IX Fee + if(coinControl->useInstantX) nFee = max(nFee, CENT); + // Min Fee int64_t nMinFee = GetMinFee(txDummy, nBytes, AllowFree(dPriority), GMF_SEND); @@ -552,6 +555,13 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog) { nChange = nAmount - nPayFee - nPayAmount; + // DS Fee = overpay + if(coinControl->useDarkSend && nChange > 0) + { + nPayFee += nChange; + nChange = 0; + } + // if sub-cent change is required, the fee must be raised to at least CTransaction::nMinTxFee if (nPayFee < CTransaction::nMinTxFee && nChange > 0 && nChange < CENT) { diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 587e002ccc..e1e1f40a3e 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -373,10 +373,12 @@ void OverviewPage::darkSendStatus() /* ** @TODO this string creation really needs some clean ups ---vertoe ** */ std::ostringstream convert; - if(state == POOL_STATUS_ACCEPTING_ENTRIES) { + if(state == POOL_STATUS_IDLE) { + convert << tr("Darksend is idle.").toStdString(); + } else if(state == POOL_STATUS_ACCEPTING_ENTRIES) { if(entries == 0) { if(darkSendPool.strAutoDenomResult.size() == 0){ - convert << tr("Darksend is idle.").toStdString(); + convert << tr("Mixing in progress...").toStdString(); } else { convert << darkSendPool.strAutoDenomResult; } diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index cbbae8626f..2564a88427 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -47,7 +47,7 @@ SendCoinsDialog::SendCoinsDialog(QWidget *parent) : connect(ui->checkBoxCoinControlChange, SIGNAL(stateChanged(int)), this, SLOT(coinControlChangeChecked(int))); connect(ui->lineEditCoinControlChange, SIGNAL(textEdited(const QString &)), this, SLOT(coinControlChangeEdited(const QString &))); connect(ui->checkUseDarksend, SIGNAL(stateChanged ( int )), this, SLOT(updateDisplayUnit())); - connect(ui->checkInstantX, SIGNAL(stateChanged ( int )), this, SLOT(updateDisplayUnit())); + connect(ui->checkInstantX, SIGNAL(stateChanged ( int )), this, SLOT(updateInstantX())); // Coin Control: clipboard actions QAction *clipboardQuantityAction = new QAction(tr("Copy quantity"), this); @@ -473,6 +473,14 @@ void SendCoinsDialog::setBalance(qint64 balance, qint64 unconfirmedBalance, qint void SendCoinsDialog::updateDisplayUnit() { setBalance(model->getBalance(), model->getUnconfirmedBalance(), model->getImmatureBalance(), model->getAnonymizedBalance()); + CoinControlDialog::coinControl->useDarkSend = ui->checkUseDarksend->isChecked(); + coinControlUpdateLabels(); +} + +void SendCoinsDialog::updateInstantX() +{ + CoinControlDialog::coinControl->useInstantX = ui->checkInstantX->isChecked(); + coinControlUpdateLabels(); } void SendCoinsDialog::processSendCoinsReturn(const WalletModel::SendCoinsReturn &sendCoinsReturn, const QString &msgArg) diff --git a/src/qt/sendcoinsdialog.h b/src/qt/sendcoinsdialog.h index 5df7795676..6f86057313 100644 --- a/src/qt/sendcoinsdialog.h +++ b/src/qt/sendcoinsdialog.h @@ -64,6 +64,7 @@ private slots: void on_sendButton_clicked(); void removeEntry(SendCoinsEntry* entry); void updateDisplayUnit(); + void updateInstantX(); void coinControlFeatureChanged(bool); void coinControlButtonClicked(); void coinControlChangeChecked(int); diff --git a/src/rpcdarksend.cpp b/src/rpcdarksend.cpp index a170c8ac4e..e738365535 100644 --- a/src/rpcdarksend.cpp +++ b/src/rpcdarksend.cpp @@ -579,17 +579,17 @@ Value masternodelist(const Array& params, bool fHelp) "masternodelist ( \"mode\" \"filter\" )\n" "Get a list of masternodes in different modes\n" "\nArguments:\n" - "1. \"mode\" (string, optional, defauls = active) The mode to run list in\n" - "2. \"filter\" (string, optional) Filter results, can be applied in few modes only\n" + "1. \"mode\" (string, optional/required to use filter, defaults = active) The mode to run list in\n" + "2. \"filter\" (string, optional) Filter results. Partial match by IP by default in all modes, additional matches in some modes\n" "\nAvailable modes:\n" - " active - Print '1' if active and '0' otherwise (can be filtered, exact match)\n" + " active - Print '1' if active and '0' otherwise (can be additionally filtered by 'true' (active only) / 'false' (non-active only))\n" " activeseconds - Print number of seconds masternode recognized by the network as enabled\n" - " full - Print info in format 'active | protocol | pubkey | vin | lastseen | activeseconds' (can be filtered, partial match)\n" + " full - Print info in format 'active protocol pubkey vin lastseen activeseconds' (can be additionally filtered, partial match)\n" " lastseen - Print timestamp of when a masternode was last seen on the network\n" - " protocol - Print protocol of a masternode (can be filtered, exact match)\n" - " pubkey - Print public key associated with a masternode (can be filtered, partial match)\n" + " protocol - Print protocol of a masternode (can be additionally filtered, exact match))\n" + " pubkey - Print public key associated with a masternode (can be additionally filtered, partial match)\n" " rank - Print rank of a masternode based on current block\n" - " vin - Print vin associated with a masternode (can be filtered, partial match)\n" + " vin - Print vin associated with a masternode (can be additionally filtered, partial match)\n" ); } @@ -599,13 +599,41 @@ Value masternodelist(const Array& params, bool fHelp) std::string strAddr = mn.addr.ToString().c_str(); if(strMode == "active"){ - if(strFilter !="" && strFilter != boost::lexical_cast(mn.IsEnabled()) && + if(strFilter !="" && strFilter != (mn.IsEnabled() ? "true" : "false") && mn.addr.ToString().find(strFilter) == string::npos) continue; obj.push_back(Pair(strAddr, (int)mn.IsEnabled())); - } else if (strMode == "vin") { - if(strFilter !="" && mn.vin.prevout.hash.ToString().find(strFilter) == string::npos && + } else if (strMode == "activeseconds") { + if(strFilter !="" && mn.addr.ToString().find(strFilter) == string::npos) continue; + obj.push_back(Pair(strAddr, (int64_t)(mn.lastTimeSeen - mn.sigTime))); + } else if (strMode == "full") { + CScript pubkey; + pubkey.SetDestination(mn.pubkey.GetID()); + CTxDestination address1; + ExtractDestination(pubkey, address1); + CBitcoinAddress address2(address1); + + std::ostringstream addrStream; + addrStream << setw(21) << strAddr; + + std::ostringstream stringStream; + stringStream << (mn.IsEnabled() ? "1" : "0") << " " << + mn.protocolVersion << " " << + address2.ToString() << " " << + mn.vin.prevout.hash.ToString() << " " << + mn.lastTimeSeen << " " << setw(8) << + (mn.lastTimeSeen - mn.sigTime); + std::string output = stringStream.str(); + stringStream << " " << strAddr; + if(strFilter !="" && stringStream.str().find(strFilter) == string::npos && + mn.addr.ToString().find(strFilter) == string::npos) continue; + obj.push_back(Pair(addrStream.str(), output)); + } else if (strMode == "lastseen") { + if(strFilter !="" && mn.addr.ToString().find(strFilter) == string::npos) continue; + obj.push_back(Pair(strAddr, (int64_t)mn.lastTimeSeen)); + } else if (strMode == "protocol") { + if(strFilter !="" && strFilter != boost::lexical_cast(mn.protocolVersion) && mn.addr.ToString().find(strFilter) == string::npos) continue; - obj.push_back(Pair(strAddr, mn.vin.prevout.hash.ToString().c_str())); + obj.push_back(Pair(strAddr, (int64_t)mn.protocolVersion)); } else if (strMode == "pubkey") { CScript pubkey; pubkey.SetDestination(mn.pubkey.GetID()); @@ -616,39 +644,13 @@ Value masternodelist(const Array& params, bool fHelp) if(strFilter !="" && address2.ToString().find(strFilter) == string::npos && mn.addr.ToString().find(strFilter) == string::npos) continue; obj.push_back(Pair(strAddr, address2.ToString().c_str())); - } else if (strMode == "protocol") { - if(strFilter !="" && strFilter != boost::lexical_cast(mn.protocolVersion) && - mn.addr.ToString().find(strFilter) == string::npos) continue; - obj.push_back(Pair(strAddr, (int64_t)mn.protocolVersion)); - } else if (strMode == "lastseen") { - if(strFilter !="" && mn.addr.ToString().find(strFilter) == string::npos) continue; - - obj.push_back(Pair(strAddr, (int64_t)mn.lastTimeSeen)); - } else if (strMode == "activeseconds") { - if(strFilter !="" && mn.addr.ToString().find(strFilter) == string::npos) continue; - - obj.push_back(Pair(strAddr, (int64_t)(mn.lastTimeSeen - mn.sigTime))); } else if (strMode == "rank") { if(strFilter !="" && mn.addr.ToString().find(strFilter) == string::npos) continue; obj.push_back(Pair(strAddr, (int)(mnodeman.GetMasternodeRank(mn.vin, chainActive.Tip()->nHeight)))); - } else if (strMode == "full") { - CScript pubkey; - pubkey.SetDestination(mn.pubkey.GetID()); - CTxDestination address1; - ExtractDestination(pubkey, address1); - CBitcoinAddress address2(address1); - - std::ostringstream stringStream; - stringStream << (mn.IsEnabled() ? "1" : "0") << " | " << - mn.protocolVersion << " | " << - address2.ToString() << " | " << - mn.vin.prevout.hash.ToString() << " | " << - mn.lastTimeSeen << " | " << - (mn.lastTimeSeen - mn.sigTime); - std::string output = stringStream.str(); - stringStream << " " << strAddr; - if(strFilter !="" && stringStream.str().find(strFilter) == string::npos) continue; - obj.push_back(Pair(strAddr, output)); + } else if (strMode == "vin") { + if(strFilter !="" && mn.vin.prevout.hash.ToString().find(strFilter) == string::npos && + mn.addr.ToString().find(strFilter) == string::npos) continue; + obj.push_back(Pair(strAddr, mn.vin.prevout.hash.ToString().c_str())); } } return obj; diff --git a/src/wallet.cpp b/src/wallet.cpp index 06a17b1ab7..3dac121c81 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1787,7 +1787,7 @@ bool CWallet::CreateCollateralTransaction(CTransaction& txCollateral, std::strin BOOST_FOREACH(CTxIn v, vCoinsCollateral) UnlockCoin(v.prevout); - strReason = "CDarkSendPool::Sign - Unable to sign collateral transaction! \n"; + strReason = "CDarksendPool::Sign - Unable to sign collateral transaction! \n"; return false; } vinNumber++; @@ -1838,7 +1838,7 @@ bool CWallet::CreateTransaction(const vector >& vecSend, LOCK2(cs_main, cs_wallet); { nFeeRet = nTransactionFee; - if(useIX && nFeeRet < CENT) nFeeRet = CENT; + if(useIX) nFeeRet = max(CENT, nFeeRet); while (true) { wtxNew.vin.clear(); @@ -1912,13 +1912,9 @@ bool CWallet::CreateTransaction(const vector >& vecSend, //over pay for denominated transactions if(coin_type == ONLY_DENOMINATED) { - nFeeRet = nChange; + nFeeRet += nChange; nChange = 0; wtxNew.mapValue["DS"] = "1"; - } else if(useIX && nFeeRet < CENT && nChange > (CENT-nFeeRet)) { - // IX has a minimum fee of 0.01 DRK - nChange -= CENT-nFeeRet; - nFeeRet = CENT; } if (nChange > 0) @@ -2173,8 +2169,7 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds) int64_t nTotalValue = GetTotalValue(vCoins); LogPrintf("PrepareDarksendDenominate - preparing darksend denominate . Got: %d \n", nTotalValue); - //-------------- - BOOST_FOREACH(CTxIn v, vCoins) + BOOST_FOREACH(CTxIn v, vCoins) LockCoin(v.prevout); // denominate our funds @@ -2216,6 +2211,7 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds) std::random_shuffle (vDenoms.begin() + (int)darkSendDenominations.size() + 1, vDenoms.end()); // Make outputs by looping through denominations randomly + BOOST_REVERSE_FOREACH(int64_t v, vDenoms){ //only use the ones that are approved bool fAccepted = false; @@ -2270,7 +2266,6 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds) if(nValueLeft == 0) break; } - } if(darkSendPool.GetDenominations(vOut) != darkSendPool.sessionDenom) @@ -2280,7 +2275,6 @@ string CWallet::PrepareDarksendDenominate(int minRounds, int maxRounds) if(nValueLeft != 0) return "Error: change left-over in pool. Must use denominations only"; - //randomize the output order std::random_shuffle (vOut.begin(), vOut.end()); diff --git a/src/wallet.h b/src/wallet.h index c8a79d4fd1..6648c41895 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -290,6 +290,7 @@ public: std::string SendMoney(CScript scriptPubKey, int64_t nValue, CWalletTx& wtxNew, AvailableCoinsType coin_type=ALL_COINS); std::string SendMoneyToDestination(const CTxDestination &address, int64_t nValue, CWalletTx& wtxNew, AvailableCoinsType coin_type=ALL_COINS); std::string PrepareDarksendDenominate(int minRounds, int maxRounds); + int GenerateDarksendOutputs(int nTotalValue, std::vector& vout); bool CreateCollateralTransaction(CTransaction& txCollateral, std::string strReason); bool ConvertList(std::vector vCoins, std::vector& vecAmounts);