2015-02-04 14:24:56 +01:00
// 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.
2014-12-09 02:17:57 +01:00
# include "darksend.h"
# include "main.h"
# include "init.h"
# include "util.h"
2015-02-23 21:01:21 +01:00
# include "masternodeman.h"
2014-12-09 02:17:57 +01:00
# include "instantx.h"
2015-02-04 14:24:56 +01:00
# include "ui_interface.h"
2014-12-09 02:17:57 +01:00
# include <boost/algorithm/string/replace.hpp>
# include <boost/filesystem.hpp>
# include <boost/filesystem/fstream.hpp>
# include <boost/lexical_cast.hpp>
# include <algorithm>
# include <boost/assign/list_of.hpp>
using namespace std ;
using namespace boost ;
2015-01-20 16:59:37 +01:00
CCriticalSection cs_darksend ;
2014-12-09 02:17:57 +01:00
/** The main object for accessing darksend */
2015-03-02 00:09:33 +01:00
CDarksendPool darkSendPool ;
2014-12-09 02:17:57 +01:00
/** A helper object for signing messages from masternodes */
CDarkSendSigner darkSendSigner ;
/** The current darksends in progress on the network */
std : : vector < CDarksendQueue > vecDarksendQueue ;
/** Keep track of the used masternodes */
std : : vector < CTxIn > vecMasternodesUsed ;
// keep track of the scanning errors I've seen
map < uint256 , CDarksendBroadcastTx > mapDarksendBroadcastTxes ;
//
CActiveMasternode activeMasternode ;
// count peers we've requested the list from
2014-12-25 20:21:35 +01:00
int RequestedMasterNodeList = 0 ;
2014-12-09 02:17:57 +01:00
/* *** BEGIN DARKSEND MAGIC - DARKCOIN **********
2014-12-25 20:21:35 +01:00
Copyright 2014 , Darkcoin Developers
2014-12-09 02:17:57 +01:00
eduffield - evan @ darkcoin . io
2015-03-02 00:09:33 +01:00
udjinm6 - udjinm6 @ darkcoin . io
2014-12-09 02:17:57 +01:00
*/
2015-03-02 00:09:33 +01:00
void CDarksendPool : : ProcessMessageDarksend ( CNode * pfrom , std : : string & strCommand , CDataStream & vRecv )
2014-12-09 02:17:57 +01:00
{
2015-01-18 16:28:16 +01:00
if ( fLiteMode ) return ; //disable all darksend/masternode related functionality
2015-02-26 15:40:43 +01:00
if ( IsInitialBlockDownload ( ) ) return ;
2015-01-18 16:28:16 +01:00
2015-03-02 00:09:33 +01:00
if ( strCommand = = " dsa " ) { //DarkSend Accept Into Pool
2015-01-19 22:25:03 +01:00
2015-02-26 18:09:39 +01:00
if ( pfrom - > nVersion < MIN_POOL_PEER_PROTO_VERSION ) {
2015-02-04 14:24:56 +01:00
std : : string strError = _ ( " Incompatible version. " ) ;
2014-12-09 02:17:57 +01:00
LogPrintf ( " dsa -- incompatible version! \n " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , strError ) ;
2014-12-09 02:17:57 +01:00
return ;
}
if ( ! fMasterNode ) {
2015-02-04 14:24:56 +01:00
std : : string strError = _ ( " This is not a masternode. " ) ;
2014-12-09 02:17:57 +01:00
LogPrintf ( " dsa -- not a masternode! \n " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , strError ) ;
2014-12-09 02:17:57 +01:00
return ;
}
int nDenom ;
CTransaction txCollateral ;
vRecv > > nDenom > > txCollateral ;
std : : string error = " " ;
2015-02-25 12:54:03 +01:00
CMasternode * pmn = mnodeman . Find ( activeMasternode . vin ) ;
if ( pmn = = NULL )
2015-02-23 21:01:21 +01:00
{
2015-02-04 14:24:56 +01:00
std : : string strError = _ ( " Not in the masternode list. " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , strError ) ;
2014-12-25 20:21:35 +01:00
return ;
2014-12-09 02:17:57 +01:00
}
2015-03-02 00:09:33 +01:00
if ( sessionUsers = = 0 ) {
2015-02-25 12:54:03 +01:00
if ( pmn - > nLastDsq ! = 0 & &
2015-03-02 00:09:33 +01:00
pmn - > nLastDsq + mnodeman . CountMasternodesAboveProtocol ( MIN_POOL_PEER_PROTO_VERSION ) / 5 > nDsqCount ) {
2015-02-25 12:54:03 +01:00
LogPrintf ( " dsa -- last dsq too recent, must wait. %s \n " , pmn - > addr . ToString ( ) . c_str ( ) ) ;
2015-02-04 14:24:56 +01:00
std : : string strError = _ ( " Last Darksend was too recent. " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , strError ) ;
2014-12-09 02:17:57 +01:00
return ;
}
}
2015-03-02 00:09:33 +01:00
if ( ! IsCompatibleWithSession ( nDenom , txCollateral , error ) )
2014-12-09 02:17:57 +01:00
{
LogPrintf ( " dsa -- not compatible with existing transactions! \n " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
} else {
LogPrintf ( " dsa -- is compatible, please submit! \n " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_ACCEPTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
}
2015-03-02 00:09:33 +01:00
2014-12-09 02:17:57 +01:00
} else if ( strCommand = = " dsq " ) { //DarkSend Queue
2015-03-02 00:09:33 +01:00
LOCK ( cs_darksend ) ;
2015-01-19 22:25:03 +01:00
2015-02-26 18:09:39 +01:00
if ( pfrom - > nVersion < MIN_POOL_PEER_PROTO_VERSION ) {
2014-12-09 02:17:57 +01:00
return ;
}
CDarksendQueue dsq ;
vRecv > > dsq ;
CService addr ;
if ( ! dsq . GetAddress ( addr ) ) return ;
if ( ! dsq . CheckSignature ( ) ) return ;
if ( dsq . IsExpired ( ) ) return ;
2015-02-25 12:54:03 +01:00
CMasternode * pmn = mnodeman . Find ( dsq . vin ) ;
if ( pmn = = NULL ) return ;
2014-12-09 02:17:57 +01:00
// if the queue is ready, submit if we can
if ( dsq . ready ) {
2015-03-02 00:09:33 +01:00
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 ( ) ) ;
2014-12-09 02:17:57 +01:00
return ;
}
2015-03-02 00:09:33 +01:00
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 ( ) ;
}
2014-12-09 02:17:57 +01:00
} else {
BOOST_FOREACH ( CDarksendQueue q , vecDarksendQueue ) {
if ( q . vin = = dsq . vin ) return ;
}
2014-12-25 20:21:35 +01:00
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " dsq last %d last2 %d count %d \n " , pmn - > nLastDsq , pmn - > nLastDsq + mnodeman . size ( ) / 5 , nDsqCount ) ;
2014-12-09 02:17:57 +01:00
//don't allow a few nodes to dominate the queuing process
2015-02-25 12:54:03 +01:00
if ( pmn - > nLastDsq ! = 0 & &
2015-03-02 00:09:33 +01:00
pmn - > nLastDsq + mnodeman . CountMasternodesAboveProtocol ( MIN_POOL_PEER_PROTO_VERSION ) / 5 > nDsqCount ) {
2015-02-25 12:54:03 +01:00
if ( fDebug ) LogPrintf ( " dsq -- masternode sending too many dsq messages. %s \n " , pmn - > addr . ToString ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
return ;
}
2015-03-02 00:09:33 +01:00
nDsqCount + + ;
pmn - > nLastDsq = nDsqCount ;
2015-02-25 12:54:03 +01:00
pmn - > allowFreeTx = true ;
2014-12-09 02:17:57 +01:00
if ( fDebug ) LogPrintf ( " dsq - new darksend queue object - %s \n " , addr . ToString ( ) . c_str ( ) ) ;
vecDarksendQueue . push_back ( dsq ) ;
dsq . Relay ( ) ;
dsq . time = GetTime ( ) ;
}
2015-03-02 00:09:33 +01:00
} 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 ;
2015-03-04 19:17:30 +01:00
2015-03-02 00:09:33 +01:00
if ( dsr . nRelayType ! = DARKSEND_RELAY_IN & &
dsr . nRelayType ! = DARKSEND_RELAY_OUT & &
dsr . nRelayType ! = DARKSEND_RELAY_SIG ) return ;
2015-03-04 19:17:30 +01:00
2015-03-02 00:09:33 +01:00
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 < std : : string > ( 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 < std : : string > ( 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 ( ) ;
2014-12-09 02:17:57 +01:00
} else if ( strCommand = = " dsi " ) { //DarkSend vIn
2015-03-02 00:09:33 +01:00
2014-12-09 02:17:57 +01:00
std : : string error = " " ;
2015-02-26 18:09:39 +01:00
if ( pfrom - > nVersion < MIN_POOL_PEER_PROTO_VERSION ) {
2014-12-09 02:17:57 +01:00
LogPrintf ( " dsi -- incompatible version! \n " ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Incompatible version. " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
}
if ( ! fMasterNode ) {
LogPrintf ( " dsi -- not a masternode! \n " ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " This is not a masternode. " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
}
std : : vector < CTxIn > in ;
int64_t nAmount ;
CTransaction txCollateral ;
std : : vector < CTxOut > out ;
vRecv > > in > > nAmount > > txCollateral > > out ;
//do we have enough users in the current session?
2015-03-02 00:09:33 +01:00
if ( ! IsSessionReady ( ) ) {
2014-12-09 02:17:57 +01:00
LogPrintf ( " dsi -- session not complete! \n " ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Session not complete! " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
}
//do we have the same denominations as the current session?
2015-03-02 00:09:33 +01:00
if ( ! IsCompatibleWithEntries ( out ) )
2014-12-09 02:17:57 +01:00
{
LogPrintf ( " dsi -- not compatible with existing transactions! \n " ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Not compatible with existing transactions. " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
}
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
//check it like a transaction
{
int64_t nValueIn = 0 ;
int64_t nValueOut = 0 ;
bool missingTx = false ;
CValidationState state ;
CTransaction tx ;
BOOST_FOREACH ( const CTxOut o , out ) {
nValueOut + = o . nValue ;
tx . vout . push_back ( o ) ;
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
if ( o . scriptPubKey . size ( ) ! = 25 ) {
LogPrintf ( " dsi - non-standard pubkey detected! %s \n " , o . scriptPubKey . ToString ( ) . c_str ( ) ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Non-standard public key detected. " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
}
if ( ! o . scriptPubKey . IsNormalPaymentScript ( ) ) {
LogPrintf ( " dsi - invalid script! %s \n " , o . scriptPubKey . ToString ( ) . c_str ( ) ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Invalid script detected. " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
}
}
BOOST_FOREACH ( const CTxIn i , in ) {
tx . vin . push_back ( i ) ;
2014-12-25 20:21:35 +01:00
if ( fDebug ) LogPrintf ( " dsi -- tx in %s \n " , i . ToString ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
2014-12-25 20:21:35 +01:00
CTransaction tx2 ;
2014-12-09 02:17:57 +01:00
uint256 hash ;
if ( GetTransaction ( i . prevout . hash , tx2 , hash , true ) ) {
if ( tx2 . vout . size ( ) > i . prevout . n ) {
2014-12-25 20:21:35 +01:00
nValueIn + = tx2 . vout [ i . prevout . n ] . nValue ;
2014-12-09 02:17:57 +01:00
}
} else {
missingTx = true ;
}
}
if ( nValueIn > DARKSEND_POOL_MAX ) {
LogPrintf ( " dsi -- more than darksend pool max! %s \n " , tx . ToString ( ) . c_str ( ) ) ;
2015-02-04 20:55:14 +01:00
error = _ ( " Value more than Darksend pool maximum allows. " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
}
if ( ! missingTx ) {
if ( nValueIn - nValueOut > nValueIn * .01 ) {
LogPrintf ( " dsi -- fees are too high! %s \n " , tx . ToString ( ) . c_str ( ) ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Transaction fees are too high. " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
}
} else {
LogPrintf ( " dsi -- missing input tx! %s \n " , tx . ToString ( ) . c_str ( ) ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Missing input transaction information. " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
}
2014-12-25 20:21:35 +01:00
if ( ! AcceptableInputs ( mempool , state , tx ) ) {
2014-12-09 02:17:57 +01:00
LogPrintf ( " dsi -- transaction not valid! \n " ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Transaction not valid. " ) ;
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
return ;
}
}
2015-03-02 00:09:33 +01:00
if ( AddEntry ( in , nAmount , txCollateral , out , error ) ) {
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_ACCEPTED , error ) ;
Check ( ) ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
RelayStatus ( sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_RESET ) ;
2014-12-09 02:17:57 +01:00
} else {
2015-03-02 00:09:33 +01:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , error ) ;
2014-12-09 02:17:57 +01:00
}
2015-03-04 19:17:30 +01:00
2015-03-02 00:09:33 +01:00
} else if ( strCommand = = " dssu " ) { //DarkSend status update
2015-01-19 22:25:03 +01:00
2015-02-26 18:09:39 +01:00
if ( pfrom - > nVersion < MIN_POOL_PEER_PROTO_VERSION ) {
2014-12-09 02:17:57 +01:00
return ;
}
2015-03-02 00:09:33 +01:00
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());
2014-12-09 02:17:57 +01:00
return ;
}
2015-03-02 00:09:33 +01:00
int sessionIDMessage ;
2014-12-09 02:17:57 +01:00
int state ;
int entriesCount ;
int accepted ;
std : : string error ;
2015-03-02 00:09:33 +01:00
vRecv > > sessionIDMessage > > state > > entriesCount > > accepted > > error ;
2014-12-09 02:17:57 +01:00
if ( fDebug ) LogPrintf ( " dssu - state: %i entriesCount: %i accepted: %i error: %s \n " , state , entriesCount , accepted , error . c_str ( ) ) ;
2015-03-02 00:09:33 +01:00
if ( ( accepted ! = 1 & & accepted ! = 0 ) & & sessionID ! = sessionIDMessage ) {
LogPrintf ( " dssu - message doesn't match current darksend session %d %d \n " , sessionID , sessionIDMessage ) ;
2014-12-09 02:17:57 +01:00
return ;
}
2014-12-25 20:21:35 +01:00
2015-03-02 00:09:33 +01:00
StatusUpdate ( state , entriesCount , accepted , error , sessionIDMessage ) ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
} else if ( strCommand = = " dss " ) { //DarkSend Sign Final Tx
2015-03-04 19:17:30 +01:00
2015-02-26 18:09:39 +01:00
if ( pfrom - > nVersion < MIN_POOL_PEER_PROTO_VERSION ) {
2014-12-09 02:17:57 +01:00
return ;
}
vector < CTxIn > sigs ;
vRecv > > sigs ;
bool success = false ;
int count = 0 ;
LogPrintf ( " -- sigs count %d %d \n " , ( int ) sigs . size ( ) , count ) ;
BOOST_FOREACH ( const CTxIn item , sigs )
{
2015-03-02 00:09:33 +01:00
if ( AddScriptSig ( item ) ) success = true ;
2014-12-09 02:17:57 +01:00
if ( fDebug ) LogPrintf ( " -- sigs count %d %d \n " , ( int ) sigs . size ( ) , count ) ;
count + + ;
}
if ( success ) {
2015-03-02 00:09:33 +01:00
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 ) ;
2015-03-04 19:17:30 +01:00
2015-03-02 00:09:33 +01:00
} else if ( strCommand = = " dsc " ) { //DarkSend Complete
2015-03-04 19:17:30 +01:00
2015-03-02 00:09:33 +01:00
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 ;
2014-12-09 02:17:57 +01:00
}
2015-03-02 00:09:33 +01:00
darkSendPool . CompletedTransaction ( error , lastMessage ) ;
2014-12-09 02:17:57 +01:00
}
}
int randomizeList ( int i ) { return std : : rand ( ) % i ; }
// Recursively determine the rounds of a given input (How deep is the darksend chain for a given input)
int GetInputDarksendRounds ( CTxIn in , int rounds )
{
2015-02-12 14:58:12 +01:00
static std : : map < uint256 , CWalletTx > mDenomWtxes ;
2015-01-14 15:52:43 +01:00
if ( rounds > = 17 ) return rounds ;
2014-12-09 02:17:57 +01:00
2015-02-12 14:58:12 +01:00
uint256 hash = in . prevout . hash ;
2015-03-04 19:17:30 +01:00
unsigned int nout = in . prevout . n ;
2014-12-09 02:17:57 +01:00
2015-02-12 14:58:12 +01:00
CWalletTx wtx ;
if ( pwalletMain - > GetTransaction ( hash , wtx ) )
2015-01-29 11:36:18 +01:00
{
2015-02-12 14:58:12 +01:00
std : : map < uint256 , CWalletTx > : : const_iterator mdwi = mDenomWtxes . find ( hash ) ;
// not known yet, let's add it
if ( mdwi = = mDenomWtxes . end ( ) )
{
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds INSERTING %s \n " , hash . ToString ( ) ) ;
mDenomWtxes [ hash ] = wtx ;
}
// found and it's not an initial value, just return it
else if ( mDenomWtxes [ hash ] . vout [ nout ] . nRounds ! = - 10 )
{
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds INFO %s %3d %d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
2014-12-09 02:17:57 +01:00
// bounds check
2015-02-12 14:58:12 +01:00
if ( nout > = wtx . vout . size ( ) )
{
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = - 4 ;
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds UPDATED %s %3d %d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
2014-12-09 02:17:57 +01:00
2015-02-12 14:58:12 +01:00
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = - 3 ;
if ( pwalletMain - > IsCollateralAmount ( wtx . vout [ nout ] . nValue ) )
{
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = - 3 ;
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds UPDATED %s %3d %d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
2014-12-09 02:17:57 +01:00
2015-01-29 11:36:18 +01:00
//make sure the final output is non-denominate
2015-02-12 14:58:12 +01:00
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = - 2 ;
if ( /*rounds == 0 && */ ! pwalletMain - > IsDenominatedAmount ( wtx . vout [ nout ] . nValue ) ) //NOT DENOM
{
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = - 2 ;
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds UPDATED %s %3d %d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
}
2014-12-09 02:17:57 +01:00
2015-02-12 14:58:12 +01:00
bool fAllDenoms = true ;
BOOST_FOREACH ( CTxOut out , wtx . vout )
{
fAllDenoms = fAllDenoms & & pwalletMain - > IsDenominatedAmount ( out . nValue ) ;
}
// this one is denominated but there is another non-denominated output found in the same tx
if ( ! fAllDenoms )
2015-01-29 11:36:18 +01:00
{
2015-02-12 14:58:12 +01:00
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = 0 ;
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds UPDATED %s %3d %d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
2014-12-09 02:17:57 +01:00
}
2015-02-12 14:58:12 +01:00
int nShortest = - 10 ; // an initial value, should be no way to get this by calculations
bool fDenomFound = false ;
// only denoms here so let's look up
BOOST_FOREACH ( CTxIn in2 , wtx . vin )
2015-01-29 11:36:18 +01:00
{
if ( pwalletMain - > IsMine ( in2 ) )
{
2014-12-09 02:17:57 +01:00
int n = GetInputDarksendRounds ( in2 , rounds + 1 ) ;
2015-02-12 14:58:12 +01:00
// denom found, find the shortest chain or initially assign nShortest with the first found value
if ( n > = 0 & & ( n < nShortest | | nShortest = = - 10 ) )
{
nShortest = n ;
fDenomFound = true ;
}
2014-12-09 02:17:57 +01:00
}
}
2015-02-12 14:58:12 +01:00
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = fDenomFound
? nShortest + 1 // good, we a +1 to the shortest one
: 0 ; // too bad, we are the fist one in that chain
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds UPDATED %s %3d %d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
2014-12-09 02:17:57 +01:00
}
return rounds - 1 ;
}
2015-03-02 00:09:33 +01:00
void CDarksendPool : : Reset ( ) {
2014-12-28 15:46:39 +01:00
cachedLastSuccess = 0 ;
vecMasternodesUsed . clear ( ) ;
2015-01-08 22:16:17 +01:00
UnlockCoins ( ) ;
2014-12-28 15:46:39 +01:00
SetNull ( ) ;
}
2015-03-02 00:09:33 +01:00
void CDarksendPool : : SetNull ( bool clearEverything ) {
2014-12-09 02:17:57 +01:00
finalTransaction . vin . clear ( ) ;
finalTransaction . vout . clear ( ) ;
entries . clear ( ) ;
2015-03-02 00:09:33 +01:00
anonTx . vin . clear ( ) ;
anonTx . vout . clear ( ) ;
fResentInputsOutputs = false ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
state = POOL_STATUS_IDLE ;
2014-12-09 02:17:57 +01:00
lastTimeChanged = GetTimeMillis ( ) ;
entriesCount = 0 ;
lastEntryAccepted = 0 ;
countEntriesAccepted = 0 ;
2015-01-27 15:46:06 +01:00
lastNewBlock = 0 ;
2015-03-02 00:09:33 +01:00
fSubmitAnonymousFailed = false ;
2014-12-09 02:17:57 +01:00
sessionUsers = 0 ;
sessionDenom = 0 ;
sessionFoundMasternode = false ;
vecSessionCollateral . clear ( ) ;
txCollateral = CTransaction ( ) ;
2015-03-02 00:09:33 +01:00
vchMasternodeRelaySig . clear ( ) ;
nMasternodeBlockHeight = 0 ;
2014-12-09 02:17:57 +01:00
if ( clearEverything ) {
myEntries . clear ( ) ;
if ( fMasterNode ) {
sessionID = 1 + ( rand ( ) % 999999 ) ;
} else {
sessionID = 0 ;
}
}
// -- seed random number generator (used for ordering output lists)
unsigned int seed = 0 ;
RAND_bytes ( ( unsigned char * ) & seed , sizeof ( seed ) ) ;
std : : srand ( seed ) ;
}
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : SetCollateralAddress ( std : : string strAddress ) {
2014-12-09 02:17:57 +01:00
CBitcoinAddress address ;
if ( ! address . SetString ( strAddress ) )
{
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::SetCollateralAddress - Invalid DarkSend collateral address \n " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
collateralPubKey . SetDestination ( address . Get ( ) ) ;
return true ;
}
//
// Unlock coins after Darksend fails or succeeds
//
2015-03-02 00:09:33 +01:00
void CDarksendPool : : UnlockCoins ( ) {
2014-12-09 02:17:57 +01:00
BOOST_FOREACH ( CTxIn v , lockedCoins )
pwalletMain - > UnlockCoin ( v . prevout ) ;
lockedCoins . clear ( ) ;
}
//
// Check the Darksend progress and send client updates if a masternode
2014-12-25 20:21:35 +01:00
//
2015-03-02 00:09:33 +01:00
void CDarksendPool : : Check ( )
2014-12-09 02:17:57 +01:00
{
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::Check() \n " ) ;
if ( fDebug ) LogPrintf ( " CDarksendPool::Check() - entries count %lu \n " , entries . size ( ) ) ;
2014-12-25 20:21:35 +01:00
2015-03-02 00:09:33 +01:00
//printf("CDarksendPool::Check() %d - %d - %d\n", state, anonTx.CountEntries(), GetTimeMillis()-lastTimeChanged);
2015-03-04 19:17:30 +01:00
2014-12-09 02:17:57 +01:00
// If entries is full, then move on to the next phase
2015-03-02 00:09:33 +01:00
if ( state = = POOL_STATUS_ACCEPTING_ENTRIES & & (
2015-03-04 19:17:30 +01:00
( int ) entries . size ( ) > = GetMaxPoolTransactions ( ) | |
2015-03-02 00:09:33 +01:00
( GetTimeMillis ( ) - lastTimeChanged > 5000 & & anonTx . CountEntries ( ) > GetMaxPoolTransactions ( ) * 5 )
) )
2014-12-09 02:17:57 +01:00
{
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::Check() -- TRYING TRANSACTION \n " ) ;
2014-12-09 02:17:57 +01:00
UpdateState ( POOL_STATUS_FINALIZE_TRANSACTION ) ;
2015-03-02 00:09:33 +01:00
nCountAttempts + + ;
2014-12-09 02:17:57 +01:00
}
// create the finalized transaction for distribution to the clients
2015-03-02 00:09:33 +01:00
if ( state = = POOL_STATUS_FINALIZE_TRANSACTION ) {
if ( fDebug ) LogPrintf ( " CDarksendPool::Check() -- FINALIZE TRANSACTIONS \n " ) ;
2014-12-09 02:17:57 +01:00
UpdateState ( POOL_STATUS_SIGNING ) ;
2014-12-25 20:21:35 +01:00
if ( fMasterNode ) {
2014-12-09 02:17:57 +01:00
CTransaction txNew ;
2015-03-02 00:09:33 +01:00
// 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 ) ;
2014-12-09 02:17:57 +01:00
}
if ( fDebug ) LogPrintf ( " Transaction 1: %s \n " , txNew . ToString ( ) . c_str ( ) ) ;
SignFinalTransaction ( txNew , NULL ) ;
2015-03-04 19:17:30 +01:00
2014-12-09 02:17:57 +01:00
// request signatures from clients
2015-03-02 00:09:33 +01:00
RelayFinalTransaction ( sessionID , finalTransaction ) ;
2014-12-09 02:17:57 +01:00
}
}
2015-03-02 00:09:33 +01:00
//printf("Signing Status %d %d\n", state == POOL_STATUS_SIGNING, SignaturesComplete());
2014-12-09 02:17:57 +01:00
// If we have all of the signatures, try to compile the transaction
2014-12-25 20:21:35 +01:00
if ( state = = POOL_STATUS_SIGNING & & SignaturesComplete ( ) ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::Check() -- SIGNING \n " ) ;
2014-12-09 02:17:57 +01:00
UpdateState ( POOL_STATUS_TRANSMISSION ) ;
2015-03-02 00:09:33 +01:00
CheckFinalTransaction ( ) ;
}
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
// 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 " ) ;
SetNull ( true ) ;
if ( fMasterNode ) RelayStatus ( darkSendPool . sessionID , darkSendPool . GetState ( ) , darkSendPool . GetEntriesCount ( ) , MASTERNODE_RESET ) ;
UnlockCoins ( ) ;
}
}
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
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 " ) ;
2014-12-09 02:17:57 +01:00
SetNull ( ) ;
pwalletMain - > Lock ( ) ;
}
2015-03-02 00:09:33 +01:00
// 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 " ) ;
2014-12-09 02:17:57 +01:00
2015-03-04 19:17:30 +01:00
if ( ! fSubmitAnonymousFailed & & nCountAttempts > 5 )
2015-03-02 00:09:33 +01:00
fSubmitAnonymousFailed = true ;
return ;
}
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::Check() -- IS MASTER -- TRANSMITTING DARKSEND \n " ) ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
// sign a message
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
int64_t sigTime = GetAdjustedTime ( ) ;
std : : string strMessage = txNew . GetHash ( ) . ToString ( ) + boost : : lexical_cast < std : : string > ( sigTime ) ;
std : : string strError = " " ;
std : : vector < unsigned char > vchSig ;
CKey key2 ;
CPubKey pubkey2 ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
if ( ! darkSendSigner . SetKey ( strMasterNodePrivKey , strError , key2 , pubkey2 ) )
{
LogPrintf ( " CDarksendPool::Check() - ERROR: Invalid masternodeprivkey: '%s' \n " , strError . c_str ( ) ) ;
return ;
}
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
if ( ! darkSendSigner . SignMessage ( strMessage , strError , vchSig , key2 ) ) {
LogPrintf ( " CDarksendPool::Check() - Sign message failed \n " ) ;
return ;
}
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
if ( ! darkSendSigner . VerifyMessage ( pubkey2 , vchSig , strMessage , strError ) ) {
LogPrintf ( " CDarksendPool::Check() - Verify message failed \n " ) ;
return ;
}
2014-12-25 20:21:35 +01:00
2015-03-02 00:09:33 +01:00
if ( ! mapDarksendBroadcastTxes . count ( txNew . GetHash ( ) ) ) {
CDarksendBroadcastTx dstx ;
dstx . tx = txNew ;
dstx . vin = activeMasternode . vin ;
dstx . vchSig = vchSig ;
dstx . sigTime = sigTime ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
mapDarksendBroadcastTxes . insert ( make_pair ( txNew . GetHash ( ) , dstx ) ) ;
2014-12-09 02:17:57 +01:00
}
2015-03-02 00:09:33 +01:00
// Broadcast the transaction to the network
txNew . fTimeReceivedIsTxTime = true ;
txNew . RelayWalletTransaction ( ) ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
// 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 ( ) ;
}
2014-12-09 02:17:57 +01:00
}
}
//
// Charge clients a fee if they're abusive
//
2014-12-25 20:21:35 +01:00
// Why bother? Darksend uses collateral to ensure abuse to the process is kept to a minimum.
// The submission and signing stages in darksend are completely separate. In the cases where
2014-12-09 02:17:57 +01:00
// a client submits a transaction then refused to sign, there must be a cost. Otherwise they
// would be able to do this over and over again and bring the mixing to a hault.
2014-12-25 20:21:35 +01:00
//
// How does this work? Messages to masternodes come in via "dsi", these require a valid collateral
2014-12-09 02:17:57 +01:00
// transaction for the client to be able to enter the pool. This transaction is kept by the masternode
2014-12-25 20:21:35 +01:00
// until the transaction is either complete or fails.
2014-12-09 02:17:57 +01:00
//
2015-03-02 00:09:33 +01:00
void CDarksendPool : : ChargeFees ( ) {
2014-12-09 02:17:57 +01:00
if ( fMasterNode ) {
//we don't need to charge collateral for every offence.
int offences = 0 ;
int r = rand ( ) % 100 ;
if ( r > 33 ) return ;
if ( state = = POOL_STATUS_ACCEPTING_ENTRIES ) {
BOOST_FOREACH ( const CTransaction & txCollateral , vecSessionCollateral ) {
bool found = false ;
BOOST_FOREACH ( const CDarkSendEntry & v , entries ) {
if ( v . collateral = = txCollateral ) {
found = true ;
}
}
// This queue entry didn't send us the promised transaction
if ( ! found ) {
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::ChargeFees -- found uncooperative node (didn't send transaction). Found offence. \n " ) ;
2014-12-09 02:17:57 +01:00
offences + + ;
}
}
}
if ( state = = POOL_STATUS_SIGNING ) {
// who didn't sign?
BOOST_FOREACH ( const CDarkSendEntry v , entries ) {
2015-03-02 00:09:33 +01:00
BOOST_FOREACH ( const CTxDSIn s , v . sev ) {
if ( ! s . fHasSig ) {
LogPrintf ( " CDarksendPool::ChargeFees -- found uncooperative node (didn't sign). Found offence \n " ) ;
2014-12-09 02:17:57 +01:00
offences + + ;
}
}
}
}
r = rand ( ) % 100 ;
int target = 0 ;
2014-12-25 20:21:35 +01:00
//mostly offending?
2014-12-09 02:17:57 +01:00
if ( offences > = POOL_MAX_TRANSACTIONS - 1 & & r > 33 ) return ;
//everyone is an offender? That's not right
if ( offences > = POOL_MAX_TRANSACTIONS ) return ;
//charge one of the offenders randomly
if ( offences > 1 ) target = 50 ;
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
//pick random client to charge
r = rand ( ) % 100 ;
if ( state = = POOL_STATUS_ACCEPTING_ENTRIES ) {
BOOST_FOREACH ( const CTransaction & txCollateral , vecSessionCollateral ) {
bool found = false ;
BOOST_FOREACH ( const CDarkSendEntry & v , entries ) {
if ( v . collateral = = txCollateral ) {
found = true ;
}
}
// This queue entry didn't send us the promised transaction
if ( ! found & & r > target ) {
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::ChargeFees -- found uncooperative node (didn't send transaction). charging fees. \n " ) ;
2014-12-09 02:17:57 +01:00
CWalletTx wtxCollateral = CWalletTx ( pwalletMain , txCollateral ) ;
// Broadcast
if ( ! wtxCollateral . AcceptToMemoryPool ( true ) )
{
// This must not fail. The transaction has already been signed and recorded.
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::ChargeFees() : Error: Transaction not valid " ) ;
2014-12-09 02:17:57 +01:00
}
wtxCollateral . RelayWalletTransaction ( ) ;
return ;
}
}
}
if ( state = = POOL_STATUS_SIGNING ) {
// who didn't sign?
BOOST_FOREACH ( const CDarkSendEntry v , entries ) {
2015-03-02 00:09:33 +01:00
BOOST_FOREACH ( const CTxDSIn s , v . sev ) {
if ( ! s . fHasSig & & r > target ) {
LogPrintf ( " CDarksendPool::ChargeFees -- found uncooperative node (didn't sign). charging fees. \n " ) ;
2014-12-09 02:17:57 +01:00
CWalletTx wtxCollateral = CWalletTx ( pwalletMain , v . collateral ) ;
// Broadcast
if ( ! wtxCollateral . AcceptToMemoryPool ( true ) )
{
// This must not fail. The transaction has already been signed and recorded.
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::ChargeFees() : Error: Transaction not valid " ) ;
2014-12-09 02:17:57 +01:00
}
wtxCollateral . RelayWalletTransaction ( ) ;
return ;
}
}
}
}
}
}
// charge the collateral randomly
// - Darksend is completely free, to pay miners we randomly pay the collateral of users.
2015-03-02 00:09:33 +01:00
void CDarksendPool : : ChargeRandomFees ( ) {
2014-12-09 02:17:57 +01:00
if ( fMasterNode ) {
int i = 0 ;
BOOST_FOREACH ( const CTransaction & txCollateral , vecSessionCollateral ) {
2015-02-17 15:04:42 +01:00
int r = rand ( ) % 100 ;
2014-12-09 02:17:57 +01:00
2015-01-02 19:45:40 +01:00
/*
Collateral Fee Charges :
Being that DarkSend has " no fees " we need to have some kind of cost associated
with using it to stop abuse . Otherwise it could serve as an attack vector and
allow endless transaction that would bloat Darkcoin and make it unusable . To
2015-02-17 15:04:42 +01:00
stop these kinds of attacks 1 in 10 successful transactions are charged . This
adds up to a cost of 0.001 DRK per transaction on average .
2015-01-02 19:45:40 +01:00
*/
2015-02-17 15:04:42 +01:00
if ( r < = 10 )
2014-12-09 02:17:57 +01:00
{
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::ChargeRandomFees -- charging random fees. %u \n " , i ) ;
2014-12-09 02:17:57 +01:00
CWalletTx wtxCollateral = CWalletTx ( pwalletMain , txCollateral ) ;
// Broadcast
if ( ! wtxCollateral . AcceptToMemoryPool ( true ) )
{
// This must not fail. The transaction has already been signed and recorded.
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::ChargeRandomFees() : Error: Transaction not valid " ) ;
2014-12-09 02:17:57 +01:00
}
wtxCollateral . RelayWalletTransaction ( ) ;
}
}
}
}
//
// Check for various timeouts (queue objects, darksend, etc)
//
2015-03-02 00:09:33 +01:00
void CDarksendPool : : CheckTimeout ( ) {
2015-01-21 14:02:59 +01:00
if ( ! fEnableDarksend & & ! fMasterNode ) return ;
2015-01-20 11:32:32 +01:00
2014-12-09 02:17:57 +01:00
// catching hanging sessions
if ( ! fMasterNode ) {
if ( state = = POOL_STATUS_TRANSMISSION ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::CheckTimeout() -- Session complete -- Running Check() \n " ) ;
2014-12-09 02:17:57 +01:00
Check ( ) ;
2014-12-25 20:21:35 +01:00
}
2014-12-09 02:17:57 +01:00
}
// check darksend queue objects for timeouts
int c = 0 ;
vector < CDarksendQueue > : : iterator it ;
for ( it = vecDarksendQueue . begin ( ) ; it < vecDarksendQueue . end ( ) ; it + + ) {
if ( ( * it ) . IsExpired ( ) ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::CheckTimeout() : Removing expired queue entry - %d \n " , c ) ;
2014-12-09 02:17:57 +01:00
vecDarksendQueue . erase ( it ) ;
break ;
}
c + + ;
}
int addLagTime = 0 ;
if ( ! fMasterNode ) addLagTime = 10000 ; //if we're the client, give the server a few extra seconds before resetting.
if ( state = = POOL_STATUS_ACCEPTING_ENTRIES | | state = = POOL_STATUS_QUEUE ) {
c = 0 ;
// if it's a masternode, the entries are stored in "entries", otherwise they're stored in myEntries
std : : vector < CDarkSendEntry > * vec = & myEntries ;
if ( fMasterNode ) vec = & entries ;
// check for a timeout and reset if needed
vector < CDarkSendEntry > : : iterator it2 ;
for ( it2 = vec - > begin ( ) ; it2 < vec - > end ( ) ; it2 + + ) {
if ( ( * it2 ) . IsExpired ( ) ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::CheckTimeout() : Removing expired entry - %d \n " , c ) ;
2014-12-09 02:17:57 +01:00
vec - > erase ( it2 ) ;
if ( entries . size ( ) = = 0 & & myEntries . size ( ) = = 0 ) {
SetNull ( true ) ;
UnlockCoins ( ) ;
}
if ( fMasterNode ) {
2015-03-02 00:09:33 +01:00
RelayStatus ( darkSendPool . sessionID , darkSendPool . GetState ( ) , darkSendPool . GetEntriesCount ( ) , MASTERNODE_RESET ) ;
2014-12-09 02:17:57 +01:00
}
break ;
}
c + + ;
}
2015-03-02 00:09:33 +01:00
if ( ! fSubmitAnonymousFailed & & ! fMasterNode & & state = = POOL_STATUS_ACCEPTING_ENTRIES ) {
if ( GetTimeMillis ( ) - lastTimeChanged > = ( DARKSEND_DOWNGRADE_TIMEOUT * 1000 ) + addLagTime ) {
lastTimeChanged = GetTimeMillis ( ) ;
Downgrade ( ) ;
}
}
2014-12-09 02:17:57 +01:00
if ( GetTimeMillis ( ) - lastTimeChanged > = ( DARKSEND_QUEUE_TIMEOUT * 1000 ) + addLagTime ) {
lastTimeChanged = GetTimeMillis ( ) ;
2014-12-25 20:21:35 +01:00
ChargeFees ( ) ;
2014-12-09 02:17:57 +01:00
// reset session information for the queue query stage (before entering a masternode, clients will send a queue request to make sure they're compatible denomination wise)
sessionUsers = 0 ;
sessionDenom = 0 ;
sessionFoundMasternode = false ;
vecSessionCollateral . clear ( ) ;
UpdateState ( POOL_STATUS_ACCEPTING_ENTRIES ) ;
}
} else if ( GetTimeMillis ( ) - lastTimeChanged > = ( DARKSEND_QUEUE_TIMEOUT * 1000 ) + addLagTime ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::CheckTimeout() -- Session timed out (30s) -- resetting \n " ) ;
2014-12-09 02:17:57 +01:00
SetNull ( ) ;
UnlockCoins ( ) ;
UpdateState ( POOL_STATUS_ERROR ) ;
2015-02-04 14:24:56 +01:00
lastMessage = _ ( " Session timed out (30 seconds), please resubmit. " ) ;
2014-12-09 02:17:57 +01:00
}
if ( state = = POOL_STATUS_SIGNING & & GetTimeMillis ( ) - lastTimeChanged > = ( DARKSEND_SIGNING_TIMEOUT * 1000 ) + addLagTime ) {
2015-03-02 00:09:33 +01:00
if ( fSubmitAnonymousFailed ) {
if ( fDebug ) LogPrintf ( " CDarksendPool::CheckTimeout() -- Session timed out -- restting \n " ) ;
ChargeFees ( ) ;
SetNull ( ) ;
UnlockCoins ( ) ;
//add my transactions to the new session
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
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 */
2015-03-04 19:17:30 +01:00
//
2015-03-02 00:09:33 +01:00
// 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 ( ) ;
2014-12-09 02:17:57 +01:00
}
}
// check to see if the signature is valid
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : SignatureValid ( const CScript & newSig , const CTxIn & newVin ) {
2014-12-09 02:17:57 +01:00
CTransaction txNew ;
txNew . vin . clear ( ) ;
txNew . vout . clear ( ) ;
int found = - 1 ;
CScript sigPubKey = CScript ( ) ;
unsigned int i = 0 ;
2015-03-02 00:09:33 +01:00
BOOST_FOREACH ( CDarkSendEntry & e , entries ) {
BOOST_FOREACH ( const CTxOut & out , e . vout )
2014-12-09 02:17:57 +01:00
txNew . vout . push_back ( out ) ;
2015-03-02 00:09:33 +01:00
BOOST_FOREACH ( const CTxDSIn & s , e . sev ) {
txNew . vin . push_back ( s ) ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
if ( s = = newVin ) {
2014-12-09 02:17:57 +01:00
found = i ;
2015-03-02 00:09:33 +01:00
sigPubKey = s . prevPubKey ;
2014-12-09 02:17:57 +01:00
}
i + + ;
}
}
if ( found > = 0 ) { //might have to do this one input at a time?
int n = found ;
txNew . vin [ n ] . scriptSig = newSig ;
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::SignatureValid() - Sign with sig %s \n " , newSig . ToString ( ) . substr ( 0 , 24 ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
if ( ! VerifyScript ( txNew . vin [ n ] . scriptSig , sigPubKey , txNew , n , SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC , 0 ) ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::SignatureValid() - Signing - Error signing input %u \n " , n ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
}
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::SignatureValid() - Signing - Successfully validated input \n " ) ;
2014-12-09 02:17:57 +01:00
return true ;
}
// check to make sure the collateral provided by the client is valid
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : IsCollateralValid ( const CTransaction & txCollateral ) {
2014-12-09 02:17:57 +01:00
if ( txCollateral . vout . size ( ) < 1 ) return false ;
if ( txCollateral . nLockTime ! = 0 ) return false ;
int64_t nValueIn = 0 ;
int64_t nValueOut = 0 ;
bool missingTx = false ;
BOOST_FOREACH ( const CTxOut o , txCollateral . vout ) {
nValueOut + = o . nValue ;
if ( ! o . scriptPubKey . IsNormalPaymentScript ( ) ) {
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::IsCollateralValid - Invalid Script %s \n " , txCollateral . ToString ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
}
BOOST_FOREACH ( const CTxIn i , txCollateral . vin ) {
CTransaction tx2 ;
uint256 hash ;
if ( GetTransaction ( i . prevout . hash , tx2 , hash , true ) ) {
if ( tx2 . vout . size ( ) > i . prevout . n ) {
2014-12-25 20:21:35 +01:00
nValueIn + = tx2 . vout [ i . prevout . n ] . nValue ;
2014-12-09 02:17:57 +01:00
}
} else {
missingTx = true ;
}
}
if ( missingTx ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::IsCollateralValid - Unknown inputs in collateral transaction - %s \n " , txCollateral . ToString ( ) . c_str ( ) ) ;
2014-12-25 20:21:35 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
//collateral transactions are required to pay out DARKSEND_COLLATERAL as a fee to the miners
2015-02-18 13:31:40 +01:00
if ( nValueIn - nValueOut < DARKSEND_COLLATERAL ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::IsCollateralValid - did not include enough fees in transaction %d \n %s \n " , nValueOut - nValueIn , txCollateral . ToString ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::IsCollateralValid %s \n " , txCollateral . ToString ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
CValidationState state ;
2014-12-29 16:50:40 +01:00
if ( ! AcceptableInputs ( mempool , state , txCollateral ) ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::IsCollateralValid - didn't pass IsAcceptable \n " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
return true ;
}
2014-12-25 20:21:35 +01:00
//
2014-12-09 02:17:57 +01:00
// Add a clients transaction to the pool
//
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : AddEntry ( const std : : vector < CTxIn > & newInput , const int64_t & nAmount , const CTransaction & txCollateral , const std : : vector < CTxOut > & newOutput , std : : string & error ) {
2014-12-09 02:17:57 +01:00
if ( ! fMasterNode ) return false ;
BOOST_FOREACH ( CTxIn in , newInput ) {
if ( in . prevout . IsNull ( ) | | nAmount < 0 ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::AddEntry - input not valid! \n " ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Input is not valid. " ) ;
2014-12-09 02:17:57 +01:00
sessionUsers - - ;
return false ;
}
}
if ( ! IsCollateralValid ( txCollateral ) ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::AddEntry - collateral not valid! \n " ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Collateral is not valid. " ) ;
2014-12-09 02:17:57 +01:00
sessionUsers - - ;
return false ;
}
if ( ( int ) entries . size ( ) > = GetMaxPoolTransactions ( ) ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::AddEntry - entries is full! \n " ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Entries are full. " ) ;
2014-12-09 02:17:57 +01:00
sessionUsers - - ;
return false ;
}
BOOST_FOREACH ( CTxIn in , newInput ) {
if ( fDebug ) LogPrintf ( " looking for vin -- %s \n " , in . ToString ( ) . c_str ( ) ) ;
2015-03-02 00:09:33 +01:00
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 " ) ;
2015-02-04 14:24:56 +01:00
error = _ ( " Already have that input. " ) ;
2014-12-09 02:17:57 +01:00
sessionUsers - - ;
return false ;
}
}
}
}
2015-03-02 00:09:33 +01:00
CDarkSendEntry v ;
v . Add ( newInput , nAmount , txCollateral , newOutput ) ;
entries . push_back ( v ) ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::AddEntry -- adding %s \n " , newInput [ 0 ] . ToString ( ) . c_str ( ) ) ;
error = " " ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
return true ;
2014-12-09 02:17:57 +01:00
}
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : AddScriptSig ( const CTxIn & newVin ) {
if ( fDebug ) LogPrintf ( " CDarksendPool::AddScriptSig -- new sig %s \n " , newVin . scriptSig . ToString ( ) . substr ( 0 , 24 ) . c_str ( ) ) ;
2014-12-25 20:21:35 +01:00
2015-03-02 00:09:33 +01:00
BOOST_FOREACH ( const CDarkSendEntry & v , entries ) {
BOOST_FOREACH ( const CTxDSIn & s , v . sev ) {
if ( s . scriptSig = = newVin . scriptSig ) {
LogPrintf ( " CDarksendPool::AddScriptSig - already exists \n " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
}
}
if ( ! SignatureValid ( newVin . scriptSig , newVin ) ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::AddScriptSig - Invalid Sig \n " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::AddScriptSig -- sig %s \n " , newVin . ToString ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
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 ;
2014-12-09 02:17:57 +01:00
}
}
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::AddScriptSig -- Couldn't set sig! \n " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
// check to make sure everything is signed
2015-03-02 00:09:33 +01:00
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 ;
2014-12-09 02:17:57 +01:00
}
}
return true ;
}
//
// Execute a darksend denomination via a masternode.
// This is only ran from clients
2014-12-25 20:21:35 +01:00
//
2015-03-02 00:09:33 +01:00
void CDarksendPool : : SendDarksendDenominate ( std : : vector < CTxIn > & vin , std : : vector < CTxOut > & vout , int64_t amount ) {
2014-12-09 02:17:57 +01:00
if ( darkSendPool . txCollateral = = CTransaction ( ) ) {
LogPrintf ( " CDarksendPool:SendDarksendDenominate() - Darksend collateral not set " ) ;
return ;
}
// lock the funds we're going to use
BOOST_FOREACH ( CTxIn in , txCollateral . vin )
lockedCoins . push_back ( in ) ;
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
BOOST_FOREACH ( CTxIn in , vin )
lockedCoins . push_back ( in ) ;
//BOOST_FOREACH(CTxOut o, vout)
// LogPrintf(" vout - %s\n", o.ToString().c_str());
// we should already be connected to a masternode
if ( ! sessionFoundMasternode ) {
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::SendDarksendDenominate() - No masternode has been selected yet. \n " ) ;
2014-12-09 02:17:57 +01:00
UnlockCoins ( ) ;
SetNull ( true ) ;
return ;
}
if ( ! CheckDiskSpace ( ) )
return ;
if ( fMasterNode ) {
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::SendDarksendDenominate() - DarkSend from a masternode is not supported currently. \n " ) ;
2014-12-09 02:17:57 +01:00
return ;
}
UpdateState ( POOL_STATUS_ACCEPTING_ENTRIES ) ;
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::SendDarksendDenominate() - Added transaction to pool. \n " ) ;
2014-12-09 02:17:57 +01:00
ClearLastMessage ( ) ;
//check it against the memory pool to make sure it's valid
{
int64_t nValueOut = 0 ;
CValidationState state ;
CTransaction tx ;
2015-03-02 00:09:33 +01:00
BOOST_FOREACH ( const CTxOut & o , vout ) {
2014-12-09 02:17:57 +01:00
nValueOut + = o . nValue ;
tx . vout . push_back ( o ) ;
}
2015-03-02 00:09:33 +01:00
BOOST_FOREACH ( const CTxIn & i , vin ) {
2014-12-09 02:17:57 +01:00
tx . vin . push_back ( i ) ;
2014-12-25 20:21:35 +01:00
if ( fDebug ) LogPrintf ( " dsi -- tx in %s \n " , i . ToString ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
}
2015-03-02 00:09:33 +01:00
printf ( " Submitting tx %s \n " , tx . ToString ( ) . c_str ( ) ) ;
2014-12-25 20:21:35 +01:00
if ( ! AcceptableInputs ( mempool , state , tx ) ) {
2014-12-09 02:17:57 +01:00
LogPrintf ( " dsi -- transaction not valid! %s \n " , tx . ToString ( ) . c_str ( ) ) ;
return ;
}
}
// store our entry for later use
CDarkSendEntry e ;
e . Add ( vin , amount , txCollateral , vout ) ;
myEntries . push_back ( e ) ;
2015-03-02 00:09:33 +01:00
// submit inputs/outputs through relays
RelayInAnon ( vin , vout ) ;
2015-03-04 19:17:30 +01:00
2014-12-09 02:17:57 +01:00
Check ( ) ;
}
// Incoming message from masternode updating the progress of darksend
// newAccepted: -1 mean's it'n not a "transaction accepted/not accepted" message, just a standard update
// 0 means transaction was not accepted
// 1 means transaction was accepted
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : StatusUpdate ( int newState , int newEntriesCount , int newAccepted , std : : string & error , int newSessionID ) {
2014-12-09 02:17:57 +01:00
if ( fMasterNode ) return false ;
if ( state = = POOL_STATUS_ERROR | | state = = POOL_STATUS_SUCCESS ) return false ;
UpdateState ( newState ) ;
entriesCount = newEntriesCount ;
2015-02-04 14:24:56 +01:00
if ( error . size ( ) > 0 ) strAutoDenomResult = _ ( " Masternode: " ) + " " + error ;
2014-12-28 15:46:39 +01:00
2014-12-09 02:17:57 +01:00
if ( newAccepted ! = - 1 ) {
lastEntryAccepted = newAccepted ;
countEntriesAccepted + = newAccepted ;
if ( newAccepted = = 0 ) {
UpdateState ( POOL_STATUS_ERROR ) ;
lastMessage = error ;
}
if ( newAccepted = = 1 ) {
sessionID = newSessionID ;
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::StatusUpdate - set sessionID to %d \n " , sessionID ) ;
2014-12-09 02:17:57 +01:00
sessionFoundMasternode = true ;
}
}
if ( newState = = POOL_STATUS_ACCEPTING_ENTRIES ) {
if ( newAccepted = = 1 ) {
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::StatusUpdate - entry accepted! \n " ) ;
2014-12-09 02:17:57 +01:00
sessionFoundMasternode = true ;
//wait for other users. Masternode will report when ready
UpdateState ( POOL_STATUS_QUEUE ) ;
2015-03-02 00:09:33 +01:00
printf ( " Updated 1 \n " ) ;
2014-12-09 02:17:57 +01:00
} else if ( newAccepted = = 0 & & sessionID = = 0 & & ! sessionFoundMasternode ) {
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::StatusUpdate - entry not accepted by masternode \n " ) ;
2014-12-09 02:17:57 +01:00
UnlockCoins ( ) ;
2014-12-23 02:17:47 +01:00
UpdateState ( POOL_STATUS_ACCEPTING_ENTRIES ) ;
2014-12-09 02:17:57 +01:00
DoAutomaticDenominating ( ) ; //try another masternode
}
if ( sessionFoundMasternode ) return true ;
}
return true ;
}
2014-12-25 20:21:35 +01:00
//
// After we receive the finalized transaction from the masternode, we must
// check it to make sure it's what we want, then sign it if we agree.
2014-12-09 02:17:57 +01:00
// If we refuse to sign, it's possible we'll be charged collateral
//
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : SignFinalTransaction ( CTransaction & finalTransactionNew , CNode * node ) {
if ( fDebug ) LogPrintf ( " CDarksendPool::SignFinalTransaction - Got Finalized Transaction - fSubmitAnonymousFailed %d \n " , fSubmitAnonymousFailed ) ;
2014-12-09 02:17:57 +01:00
finalTransaction = finalTransactionNew ;
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::SignFinalTransaction %s \n " , finalTransaction . ToString ( ) . c_str ( ) ) ;
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
vector < CTxIn > sigs ;
//make sure my inputs/outputs are present, otherwise refuse to sign
BOOST_FOREACH ( const CDarkSendEntry e , myEntries ) {
2015-03-02 00:09:33 +01:00
BOOST_FOREACH ( const CTxDSIn s , e . sev ) {
2014-12-09 02:17:57 +01:00
/* Sign my transaction and all outputs */
int mine = - 1 ;
CScript prevPubKey = CScript ( ) ;
CTxIn vin = CTxIn ( ) ;
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
for ( unsigned int i = 0 ; i < finalTransaction . vin . size ( ) ; i + + ) {
2015-03-02 00:09:33 +01:00
if ( finalTransaction . vin [ i ] = = s ) {
2014-12-09 02:17:57 +01:00
mine = i ;
2015-03-02 00:09:33 +01:00
prevPubKey = s . prevPubKey ;
vin = s ;
2014-12-09 02:17:57 +01:00
}
}
if ( mine > = 0 ) { //might have to do this one input at a time?
int foundOutputs = 0 ;
int64_t nValue1 = 0 ;
int64_t nValue2 = 0 ;
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
for ( unsigned int i = 0 ; i < finalTransaction . vout . size ( ) ; i + + ) {
2015-03-02 00:09:33 +01:00
BOOST_FOREACH ( const CTxOut & o , e . vout ) {
2014-12-09 02:17:57 +01:00
if ( finalTransaction . vout [ i ] = = o ) {
foundOutputs + + ;
nValue1 + = finalTransaction . vout [ i ] . nValue ;
}
}
}
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
BOOST_FOREACH ( const CTxOut o , e . vout )
nValue2 + = o . nValue ;
int targetOuputs = e . vout . size ( ) ;
if ( foundOutputs < targetOuputs | | nValue1 ! = nValue2 ) {
2014-12-25 20:21:35 +01:00
// in this case, something went wrong and we'll refuse to sign. It's possible we'll be charged collateral. But that's
2014-12-09 02:17:57 +01:00
// better then signing if the transaction doesn't look like what we wanted.
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::Sign - My entries are not correct! Refusing to sign. %d entries %d target. \n " , foundOutputs , targetOuputs ) ;
ResendMissingInputsOutputs ( ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::Sign - Signing my input %i \n " , mine ) ;
2014-12-09 02:17:57 +01:00
if ( ! SignSignature ( * pwalletMain , prevPubKey , finalTransaction , mine , int ( SIGHASH_ALL | SIGHASH_ANYONECANPAY ) ) ) { // changes scriptSig
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::Sign - Unable to sign my own transaction! \n " ) ;
2014-12-09 02:17:57 +01:00
// not sure what to do here, it will timeout...?
}
sigs . push_back ( finalTransaction . vin [ mine ] ) ;
2015-03-04 19:17:30 +01:00
if ( fDebug ) LogPrintf ( " -- dss %d %d %s \n " , mine , ( int ) sigs . size ( ) , finalTransaction . vin [ mine ] . scriptSig . ToString ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
}
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
}
2014-12-25 20:21:35 +01:00
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::Sign - txNew: \n %s " , finalTransaction . ToString ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
}
2015-03-02 00:09:33 +01:00
if ( ! fSubmitAnonymousFailed ) {
RelaySignaturesAnon ( sigs ) ;
} else {
// push all of our signatures to the masternode
if ( sigs . size ( ) > 0 & & node ! = NULL )
node - > PushMessage ( " dss " , sigs ) ;
}
2014-12-09 02:17:57 +01:00
return true ;
}
2015-03-02 00:09:33 +01:00
void CDarksendPool : : NewBlock ( )
2014-12-09 02:17:57 +01:00
{
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::NewBlock \n " ) ;
2014-12-09 02:17:57 +01:00
2015-01-27 15:46:06 +01:00
//we we're processing lots of blocks, we'll just leave
if ( GetTime ( ) - lastNewBlock < 10 ) return ;
lastNewBlock = GetTime ( ) ;
darkSendPool . CheckTimeout ( ) ;
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
if ( ! fEnableDarksend ) return ;
if ( ! fMasterNode ) {
//denominate all non-denominated inputs every 25 minutes.
if ( chainActive . Tip ( ) - > nHeight % 10 = = 0 ) UnlockCoins ( ) ;
}
}
// Darksend transaction was completed (failed or successed)
2015-03-02 00:09:33 +01:00
void CDarksendPool : : CompletedTransaction ( bool error , std : : string lastMessageNew )
2014-12-09 02:17:57 +01:00
{
if ( fMasterNode ) return ;
if ( error ) {
LogPrintf ( " CompletedTransaction -- error \n " ) ;
UpdateState ( POOL_STATUS_ERROR ) ;
2015-03-02 00:09:33 +01:00
Check ( ) ;
2015-03-04 19:17:30 +01:00
UnlockCoins ( ) ;
2014-12-09 02:17:57 +01:00
} else {
LogPrintf ( " CompletedTransaction -- success \n " ) ;
UpdateState ( POOL_STATUS_SUCCESS ) ;
myEntries . clear ( ) ;
2015-03-02 00:09:33 +01:00
UnlockCoins ( ) ;
if ( ! fMasterNode ) SetNull ( true ) ;
2014-12-09 02:17:57 +01:00
// To avoid race conditions, we'll only let DS run once per block
cachedLastSuccess = chainActive . Tip ( ) - > nHeight ;
}
lastMessage = lastMessageNew ;
completedTransaction = true ;
}
2015-03-02 00:09:33 +01:00
void CDarksendPool : : ClearLastMessage ( )
2014-12-09 02:17:57 +01:00
{
lastMessage = " " ;
}
2014-12-25 20:21:35 +01:00
//
2014-12-09 02:17:57 +01:00
// Passively run Darksend in the background to anonymize funds based on the given configuration.
//
2014-12-25 20:21:35 +01:00
// This does NOT run by default for daemons, only for QT.
2014-12-09 02:17:57 +01:00
//
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : DoAutomaticDenominating ( bool fDryRun , bool ready )
2014-12-09 02:17:57 +01:00
{
2015-01-20 16:59:37 +01:00
LOCK ( cs_darksend ) ;
2015-01-29 23:19:41 +01:00
if ( IsInitialBlockDownload ( ) ) return false ;
2014-12-09 02:17:57 +01:00
if ( fMasterNode ) return false ;
if ( state = = POOL_STATUS_ERROR | | state = = POOL_STATUS_SUCCESS ) return false ;
2015-01-25 22:18:26 +01:00
if ( chainActive . Tip ( ) - > nHeight - cachedLastSuccess < minBlockSpacing ) {
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::DoAutomaticDenominating - Last successful darksend action was too recent \n " ) ;
2015-02-04 14:24:56 +01:00
strAutoDenomResult = _ ( " Last successful darksend action was too recent. " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
if ( ! fEnableDarksend ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::DoAutomaticDenominating - Darksend is disabled \n " ) ;
2015-02-04 14:24:56 +01:00
strAutoDenomResult = _ ( " Darksend is disabled. " ) ;
2014-12-25 20:21:35 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
if ( ! fDryRun & & pwalletMain - > IsLocked ( ) ) {
2015-02-04 14:24:56 +01:00
strAutoDenomResult = _ ( " Wallet is locked. " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
if ( darkSendPool . GetState ( ) ! = POOL_STATUS_ERROR & & darkSendPool . GetState ( ) ! = POOL_STATUS_SUCCESS ) {
if ( darkSendPool . GetMyTransactionCount ( ) > 0 ) {
return true ;
}
2014-12-25 20:21:35 +01:00
}
2014-12-09 02:17:57 +01:00
2015-02-23 21:01:21 +01:00
if ( mnodeman . size ( ) = = 0 ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::DoAutomaticDenominating - No masternodes detected \n " ) ;
2015-02-04 14:24:56 +01:00
strAutoDenomResult = _ ( " No masternodes detected. " ) ;
2014-12-28 02:08:45 +01:00
return false ;
}
2014-12-09 02:17:57 +01:00
// ** find the coins we'll use
std : : vector < CTxIn > vCoins ;
2015-01-20 16:59:37 +01:00
std : : vector < COutput > vCoins2 ;
2015-01-25 22:18:26 +01:00
int64_t nValueMin = CENT ;
2014-12-09 02:17:57 +01:00
int64_t nValueIn = 0 ;
2015-02-18 13:31:40 +01:00
// should not be less than fees in DARKSEND_COLLATERAL + few (lets say 5) smallest denoms
int64_t nLowestDenom = DARKSEND_COLLATERAL + darkSendDenominations [ darkSendDenominations . size ( ) - 1 ] * 5 ;
2015-01-21 07:09:04 +01:00
2015-01-27 05:13:34 +01:00
// if there are no DS collateral inputs yet
if ( ! pwalletMain - > HasCollateralInputs ( ) )
2015-01-21 07:09:04 +01:00
// should have some additional amount for them
2015-02-18 13:31:40 +01:00
nLowestDenom + = DARKSEND_COLLATERAL * 4 ;
2015-01-21 07:09:04 +01:00
int64_t nBalanceNeedsAnonymized = nAnonymizeDarkcoinAmount * COIN - pwalletMain - > GetAnonymizedBalance ( ) ;
2015-01-15 15:41:56 +01:00
// if balanceNeedsAnonymized is more than pool max, take the pool max
2015-01-21 07:09:04 +01:00
if ( nBalanceNeedsAnonymized > DARKSEND_POOL_MAX ) nBalanceNeedsAnonymized = DARKSEND_POOL_MAX ;
2015-01-15 15:41:56 +01:00
2015-01-25 00:57:55 +01:00
// if balanceNeedsAnonymized is more than non-anonymized, take non-anonymized
int64_t nBalanceNotYetAnonymized = pwalletMain - > GetBalance ( ) - pwalletMain - > GetAnonymizedBalance ( ) ;
2015-01-21 07:09:04 +01:00
if ( nBalanceNeedsAnonymized > nBalanceNotYetAnonymized ) nBalanceNeedsAnonymized = nBalanceNotYetAnonymized ;
2014-12-09 02:17:57 +01:00
2015-01-21 07:09:04 +01:00
if ( nBalanceNeedsAnonymized < nLowestDenom )
{
2015-03-02 00:09:33 +01:00
LogPrintf ( " DoAutomaticDenominating : No funds detected in need of denominating \n " ) ;
strAutoDenomResult = _ ( " No funds detected in need of denominating. " ) ;
return false ;
2014-12-09 02:17:57 +01:00
}
2015-01-25 00:57:55 +01:00
if ( fDebug ) LogPrintf ( " DoAutomaticDenominating : nLowestDenom=%d, nBalanceNeedsAnonymized=%d \n " , nLowestDenom , nBalanceNeedsAnonymized ) ;
2014-12-09 02:17:57 +01:00
// select coins that should be given to the pool
2015-01-21 07:09:04 +01:00
if ( ! pwalletMain - > SelectCoinsDark ( nValueMin , nBalanceNeedsAnonymized , vCoins , nValueIn , 0 , nDarksendRounds ) )
2014-12-09 02:17:57 +01:00
{
nValueIn = 0 ;
vCoins . clear ( ) ;
2015-01-15 15:41:56 +01:00
if ( pwalletMain - > SelectCoinsDark ( nValueMin , 9999999 * COIN , vCoins , nValueIn , - 2 , 0 ) )
2014-12-09 02:17:57 +01:00
{
2015-01-21 07:09:04 +01:00
if ( ! fDryRun ) return CreateDenominated ( nBalanceNeedsAnonymized ) ;
2014-12-09 02:17:57 +01:00
return true ;
2015-01-15 15:41:56 +01:00
} else {
2015-01-25 00:57:55 +01:00
LogPrintf ( " DoAutomaticDenominating : Can't denominate - no compatible inputs left \n " ) ;
2015-02-04 14:24:56 +01:00
strAutoDenomResult = _ ( " Can't denominate: no compatible inputs left. " ) ;
2015-01-15 15:41:56 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
}
2015-01-27 05:13:34 +01:00
//check to see if we have the collateral sized inputs, it requires these
if ( ! pwalletMain - > HasCollateralInputs ( ) ) {
2015-01-25 22:18:26 +01:00
if ( ! fDryRun ) MakeCollateralAmounts ( ) ;
2014-12-09 02:17:57 +01:00
return true ;
}
if ( fDryRun ) return true ;
2015-03-02 00:09:33 +01:00
std : : vector < CTxOut > vOut ;
2014-12-09 02:17:57 +01:00
// initial phase, find a masternode
if ( ! sessionFoundMasternode ) {
int nUseQueue = rand ( ) % 100 ;
sessionTotalValue = pwalletMain - > GetTotalValue ( vCoins ) ;
//randomize the amounts we mix
2015-01-21 07:09:04 +01:00
if ( sessionTotalValue > nBalanceNeedsAnonymized ) sessionTotalValue = nBalanceNeedsAnonymized ;
2014-12-09 02:17:57 +01:00
2014-12-26 21:00:56 +01:00
double fDarkcoinSubmitted = ( sessionTotalValue / CENT ) ;
2015-01-21 07:09:04 +01:00
LogPrintf ( " Submitting Darksend for %f DRK CENT - sessionTotalValue %d \n " , fDarkcoinSubmitted , sessionTotalValue ) ;
2014-12-09 02:17:57 +01:00
2014-12-25 20:21:35 +01:00
if ( pwalletMain - > GetDenominatedBalance ( true , true ) > 0 ) { //get denominated unconfirmed inputs
2014-12-09 02:17:57 +01:00
LogPrintf ( " DoAutomaticDenominating -- Found unconfirmed denominated outputs, will wait till they confirm to continue. \n " ) ;
2015-02-04 14:24:56 +01:00
strAutoDenomResult = _ ( " Found unconfirmed denominated outputs, will wait till they confirm to continue. " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
//don't use the queues all of the time for mixing
if ( nUseQueue > 33 ) {
// Look through the queues and see if anything matches
BOOST_FOREACH ( CDarksendQueue & dsq , vecDarksendQueue ) {
CService addr ;
if ( dsq . time = = 0 ) continue ;
2014-12-30 01:09:34 +01:00
2014-12-09 02:17:57 +01:00
if ( ! dsq . GetAddress ( addr ) ) continue ;
if ( dsq . IsExpired ( ) ) continue ;
int protocolVersion ;
if ( ! dsq . GetProtocolVersion ( protocolVersion ) ) continue ;
2015-02-26 18:09:39 +01:00
if ( protocolVersion < MIN_POOL_PEER_PROTO_VERSION ) continue ;
2014-12-09 02:17:57 +01:00
2015-01-19 22:25:03 +01:00
//non-denom's are incompatible
if ( ( dsq . nDenom & ( 1 < < 4 ) ) ) continue ;
2014-12-09 02:17:57 +01:00
//don't reuse masternodes
BOOST_FOREACH ( CTxIn usedVin , vecMasternodesUsed ) {
if ( dsq . vin = = usedVin ) {
continue ;
}
}
2014-12-30 01:09:34 +01:00
// Try to match their denominations if possible
2015-01-21 07:09:04 +01:00
if ( ! pwalletMain - > SelectCoinsByDenominations ( dsq . nDenom , nValueMin , nBalanceNeedsAnonymized , vCoins , vCoins2 , nValueIn , 0 , nDarksendRounds ) ) {
2015-01-20 16:59:37 +01:00
LogPrintf ( " DoAutomaticDenominating - Couldn't match denominations %d \n " , dsq . nDenom ) ;
continue ;
2014-12-09 02:17:57 +01:00
}
// connect to masternode and submit the queue request
if ( ConnectNode ( ( CAddress ) addr , NULL , true ) ) {
2015-03-02 00:09:33 +01:00
CNode * pNode = FindNode ( addr ) ;
if ( pNode )
2014-12-09 02:17:57 +01:00
{
std : : string strReason ;
if ( txCollateral = = CTransaction ( ) ) {
if ( ! pwalletMain - > CreateCollateralTransaction ( txCollateral , strReason ) ) {
LogPrintf ( " DoAutomaticDenominating -- dsa error:%s \n " , strReason . c_str ( ) ) ;
2014-12-25 20:21:35 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
}
2014-12-25 20:21:35 +01:00
2015-03-02 00:09:33 +01:00
pSubmittedToMasternode = mnodeman . Find ( dsq . vin ) ;
2014-12-09 02:17:57 +01:00
vecMasternodesUsed . push_back ( dsq . vin ) ;
2014-12-30 01:09:34 +01:00
sessionDenom = dsq . nDenom ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
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 ( ) ) ;
2014-12-28 15:46:39 +01:00
strAutoDenomResult = " " ;
2014-12-09 02:17:57 +01:00
return true ;
}
} else {
LogPrintf ( " DoAutomaticDenominating --- error connecting \n " ) ;
2015-02-04 14:24:56 +01:00
strAutoDenomResult = _ ( " Error connecting to masternode. " ) ;
2014-12-09 02:17:57 +01:00
return DoAutomaticDenominating ( ) ;
}
2014-12-30 01:09:34 +01:00
dsq . time = 0 ; //remove node
2014-12-09 02:17:57 +01:00
}
}
2015-01-20 16:59:37 +01:00
int i = 0 ;
2014-12-09 02:17:57 +01:00
2015-01-20 16:59:37 +01:00
// otherwise, try one randomly
while ( i < 10 )
{
2015-02-26 02:55:27 +01:00
CMasternode * pmn = mnodeman . FindRandom ( ) ;
if ( pmn = = NULL )
{
LogPrintf ( " DoAutomaticDenominating --- masternode list is empty! \n " ) ;
return false ;
}
2014-12-09 02:17:57 +01:00
//don't reuse masternodes
BOOST_FOREACH ( CTxIn usedVin , vecMasternodesUsed ) {
2015-02-26 02:55:27 +01:00
if ( pmn - > vin = = usedVin ) {
2015-01-20 16:59:37 +01:00
i + + ;
continue ;
2014-12-09 02:17:57 +01:00
}
}
2015-02-26 18:09:39 +01:00
if ( pmn - > protocolVersion < MIN_POOL_PEER_PROTO_VERSION ) {
2015-01-20 16:59:37 +01:00
i + + ;
continue ;
2014-12-09 02:17:57 +01:00
}
2015-02-26 02:55:27 +01:00
if ( pmn - > nLastDsq ! = 0 & &
2015-02-26 18:09:39 +01:00
pmn - > nLastDsq + mnodeman . CountMasternodesAboveProtocol ( MIN_POOL_PEER_PROTO_VERSION ) / 5 > darkSendPool . nDsqCount ) {
2015-01-20 16:59:37 +01:00
i + + ;
continue ;
2014-12-09 02:17:57 +01:00
}
lastTimeChanged = GetTimeMillis ( ) ;
2015-02-26 02:55:27 +01:00
LogPrintf ( " DoAutomaticDenominating -- attempt %d connection to masternode %s \n " , i , pmn - > addr . ToString ( ) . c_str ( ) ) ;
if ( ConnectNode ( ( CAddress ) pmn - > addr , NULL , true ) ) {
2015-01-19 22:25:03 +01:00
2014-12-09 02:17:57 +01:00
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
{
2015-02-26 02:55:27 +01:00
if ( ( CNetAddr ) pnode - > addr ! = ( CNetAddr ) pmn - > addr ) continue ;
2014-12-09 02:17:57 +01:00
std : : string strReason ;
if ( txCollateral = = CTransaction ( ) ) {
if ( ! pwalletMain - > CreateCollateralTransaction ( txCollateral , strReason ) ) {
2015-01-20 16:59:37 +01:00
LogPrintf ( " DoAutomaticDenominating -- create collateral error:%s \n " , strReason . c_str ( ) ) ;
2014-12-25 20:21:35 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
}
2015-03-02 00:09:33 +01:00
pSubmittedToMasternode = pmn ;
2015-02-26 02:55:27 +01:00
vecMasternodesUsed . push_back ( pmn - > vin ) ;
2014-12-09 02:17:57 +01:00
2015-01-15 15:41:56 +01:00
std : : vector < int64_t > vecAmounts ;
pwalletMain - > ConvertList ( vCoins , vecAmounts ) ;
sessionDenom = GetDenominationsByAmounts ( vecAmounts ) ;
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
pnode - > PushMessage ( " dsa " , sessionDenom , txCollateral ) ;
LogPrintf ( " DoAutomaticDenominating --- connected, sending dsa for %d - denom %d \n " , sessionDenom , GetDenominationsByAmount ( sessionTotalValue ) ) ;
2014-12-28 15:46:39 +01:00
strAutoDenomResult = " " ;
2014-12-09 02:17:57 +01:00
return true ;
}
} else {
2015-01-20 16:59:37 +01:00
i + + ;
continue ;
2014-12-09 02:17:57 +01:00
}
}
2015-01-20 16:59:37 +01:00
2015-02-04 14:24:56 +01:00
strAutoDenomResult = _ ( " No compatible masternode found. " ) ;
2015-01-20 16:59:37 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
2014-12-28 15:46:39 +01:00
strAutoDenomResult = " " ;
2014-12-09 02:17:57 +01:00
if ( ! ready ) return true ;
if ( sessionDenom = = 0 ) return true ;
2015-01-08 22:16:17 +01:00
2015-01-06 22:05:39 +01:00
return false ;
2014-12-30 01:09:34 +01:00
}
2014-12-09 02:17:57 +01:00
2014-12-30 01:09:34 +01:00
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : PrepareDarksendDenominate ( )
2014-12-30 01:09:34 +01:00
{
2014-12-09 02:17:57 +01:00
// Submit transaction to the pool if we get here, use sessionDenom so we use the same amount of money
2015-01-15 15:41:56 +01:00
std : : string strError = pwalletMain - > PrepareDarksendDenominate ( 0 , nDarksendRounds ) ;
2014-12-09 02:17:57 +01:00
LogPrintf ( " DoAutomaticDenominating : Running darksend denominate. Return '%s' \n " , strError . c_str ( ) ) ;
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
if ( strError = = " " ) return true ;
2014-12-30 01:09:34 +01:00
strAutoDenomResult = strError ;
2014-12-09 02:17:57 +01:00
LogPrintf ( " DoAutomaticDenominating : Error running denominate, %s \n " , strError . c_str ( ) ) ;
return false ;
}
2015-03-02 00:09:33 +01:00
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 ( )
2014-12-09 02:17:57 +01:00
{
int64_t nBalance = pwalletMain - > GetBalance ( ) ;
int64_t nPayment = ( nBalance * 0.35 ) + ( rand ( ) % nBalance ) ;
if ( nPayment > nBalance ) nPayment = nBalance - ( 0.1 * COIN ) ;
// make our change address
CReserveKey reservekey ( pwalletMain ) ;
CScript scriptChange ;
CPubKey vchPubKey ;
assert ( reservekey . GetReservedKey ( vchPubKey ) ) ; // should never fail, as we just unlocked
scriptChange . SetDestination ( vchPubKey . GetID ( ) ) ;
CWalletTx wtx ;
int64_t nFeeRet = 0 ;
std : : string strFail = " " ;
vector < pair < CScript , int64_t > > vecSend ;
// ****** Add fees ************ /
vecSend . push_back ( make_pair ( scriptChange , nPayment ) ) ;
CCoinControl * coinControl = NULL ;
bool success = pwalletMain - > CreateTransaction ( vecSend , wtx , reservekey , nFeeRet , strFail , coinControl , ONLY_DENOMINATED ) ;
if ( ! success ) {
LogPrintf ( " SendRandomPaymentToSelf: Error - %s \n " , strFail . c_str ( ) ) ;
return false ;
}
pwalletMain - > CommitTransaction ( wtx , reservekey ) ;
LogPrintf ( " SendRandomPaymentToSelf Success: tx %s \n " , wtx . GetHash ( ) . GetHex ( ) . c_str ( ) ) ;
return true ;
}
// Split up large inputs or create fee sized inputs
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : MakeCollateralAmounts ( )
2014-12-09 02:17:57 +01:00
{
// make our change address
CReserveKey reservekey ( pwalletMain ) ;
CScript scriptChange ;
CPubKey vchPubKey ;
assert ( reservekey . GetReservedKey ( vchPubKey ) ) ; // should never fail, as we just unlocked
scriptChange . SetDestination ( vchPubKey . GetID ( ) ) ;
CWalletTx wtx ;
int64_t nFeeRet = 0 ;
std : : string strFail = " " ;
vector < pair < CScript , int64_t > > vecSend ;
2015-02-18 13:31:40 +01:00
vecSend . push_back ( make_pair ( scriptChange , DARKSEND_COLLATERAL * 4 ) ) ;
2014-12-09 02:17:57 +01:00
CCoinControl * coinControl = NULL ;
2015-01-27 05:39:27 +01:00
// try to use non-denominated and not mn-like funds
bool success = pwalletMain - > CreateTransaction ( vecSend , wtx , reservekey ,
nFeeRet , strFail , coinControl , ONLY_NONDENOMINATED_NOTMN ) ;
2014-12-09 02:17:57 +01:00
if ( ! success ) {
2015-01-27 05:39:27 +01:00
// if we failed (most likeky not enough funds), try to use denominated instead -
// MN-like funds should not be touched in any case and we can't mix denominated without collaterals anyway
success = pwalletMain - > CreateTransaction ( vecSend , wtx , reservekey ,
nFeeRet , strFail , coinControl , ONLY_DENOMINATED ) ;
if ( ! success ) {
LogPrintf ( " MakeCollateralAmounts: Error - %s \n " , strFail . c_str ( ) ) ;
return false ;
}
2014-12-09 02:17:57 +01:00
}
2015-01-25 22:18:26 +01:00
// use the same cachedLastSuccess as for DS mixinx to prevent race
if ( pwalletMain - > CommitTransaction ( wtx , reservekey ) )
cachedLastSuccess = chainActive . Tip ( ) - > nHeight ;
2014-12-09 02:17:57 +01:00
2015-01-25 22:18:26 +01:00
LogPrintf ( " MakeCollateralAmounts Success: tx %s \n " , wtx . GetHash ( ) . GetHex ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
return true ;
}
2015-01-15 15:41:56 +01:00
// Create denominations
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : CreateDenominated ( int64_t nTotalValue )
2015-01-15 15:41:56 +01:00
{
// make our change address
CReserveKey reservekey ( pwalletMain ) ;
CScript scriptChange ;
CPubKey vchPubKey ;
assert ( reservekey . GetReservedKey ( vchPubKey ) ) ; // should never fail, as we just unlocked
scriptChange . SetDestination ( vchPubKey . GetID ( ) ) ;
CWalletTx wtx ;
int64_t nFeeRet = 0 ;
std : : string strFail = " " ;
vector < pair < CScript , int64_t > > vecSend ;
int64_t nValueLeft = nTotalValue ;
2015-01-27 05:13:34 +01:00
// ****** Add collateral outputs ************ /
if ( ! pwalletMain - > HasCollateralInputs ( ) ) {
2015-02-18 13:31:40 +01:00
vecSend . push_back ( make_pair ( scriptChange , DARKSEND_COLLATERAL * 4 ) ) ;
nValueLeft - = DARKSEND_COLLATERAL * 4 ;
2015-01-21 07:09:04 +01:00
}
2015-01-15 15:41:56 +01:00
// ****** Add denoms ************ /
BOOST_REVERSE_FOREACH ( int64_t v , darkSendDenominations ) {
int nOutputs = 0 ;
// add each output up to 10 times until it can't be added again
2015-02-18 13:31:40 +01:00
while ( nValueLeft - v > = DARKSEND_COLLATERAL & & nOutputs < = 10 ) {
2015-01-15 15:41:56 +01:00
CScript scriptChange ;
CPubKey vchPubKey ;
//use a unique change address
assert ( reservekey . GetReservedKey ( vchPubKey ) ) ; // should never fail, as we just unlocked
scriptChange . SetDestination ( vchPubKey . GetID ( ) ) ;
reservekey . KeepKey ( ) ;
vecSend . push_back ( make_pair ( scriptChange , v ) ) ;
//increment outputs and subtract denomination amount
nOutputs + + ;
nValueLeft - = v ;
LogPrintf ( " CreateDenominated1 %d \n " , nValueLeft ) ;
}
if ( nValueLeft = = 0 ) break ;
}
LogPrintf ( " CreateDenominated2 %d \n " , nValueLeft ) ;
2015-01-21 07:09:04 +01:00
// if we have anything left over, it will be automatically send back as change - there is no need to send it manually
2015-01-15 15:41:56 +01:00
CCoinControl * coinControl = NULL ;
bool success = pwalletMain - > CreateTransaction ( vecSend , wtx , reservekey ,
2015-01-25 22:18:26 +01:00
nFeeRet , strFail , coinControl , ONLY_NONDENOMINATED_NOTMN ) ;
2015-01-15 15:41:56 +01:00
if ( ! success ) {
LogPrintf ( " CreateDenominated: Error - %s \n " , strFail . c_str ( ) ) ;
return false ;
}
2015-01-25 22:18:26 +01:00
// use the same cachedLastSuccess as for DS mixinx to prevent race
if ( pwalletMain - > CommitTransaction ( wtx , reservekey ) )
cachedLastSuccess = chainActive . Tip ( ) - > nHeight ;
2015-01-15 15:41:56 +01:00
LogPrintf ( " CreateDenominated Success: tx %s \n " , wtx . GetHash ( ) . GetHex ( ) . c_str ( ) ) ;
return true ;
}
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : IsCompatibleWithEntries ( std : : vector < CTxOut > & vout )
2014-12-09 02:17:57 +01:00
{
BOOST_FOREACH ( const CDarkSendEntry v , entries ) {
LogPrintf ( " IsCompatibleWithEntries %d %d \n " , GetDenominations ( vout ) , GetDenominations ( v . vout ) ) ;
/*
BOOST_FOREACH ( CTxOut o1 , vout )
LogPrintf ( " vout 1 - %s \n " , o1 . ToString ( ) . c_str ( ) ) ;
BOOST_FOREACH ( CTxOut o2 , v . vout )
LogPrintf ( " vout 2 - %s \n " , o2 . ToString ( ) . c_str ( ) ) ;
*/
if ( GetDenominations ( vout ) ! = GetDenominations ( v . vout ) ) return false ;
}
return true ;
}
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : IsCompatibleWithSession ( int64_t nDenom , CTransaction txCollateral , std : : string & strReason )
2014-12-09 02:17:57 +01:00
{
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::IsCompatibleWithSession - sessionDenom %d sessionUsers %d \n " , sessionDenom , sessionUsers ) ;
2014-12-09 02:17:57 +01:00
if ( ! unitTest & & ! IsCollateralValid ( txCollateral ) ) {
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::IsCompatibleWithSession - collateral not valid! \n " ) ;
2015-02-04 14:24:56 +01:00
strReason = _ ( " Collateral not valid. " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
if ( sessionUsers < 0 ) sessionUsers = 0 ;
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
if ( sessionUsers = = 0 ) {
sessionDenom = nDenom ;
sessionUsers + + ;
lastTimeChanged = GetTimeMillis ( ) ;
entries . clear ( ) ;
if ( ! unitTest ) {
2015-03-02 00:09:33 +01:00
//broadcast that I'm accepting entries, only if it's the first entry through
2014-12-09 02:17:57 +01:00
CDarksendQueue dsq ;
dsq . nDenom = nDenom ;
2014-12-06 20:41:53 +01:00
dsq . vin = activeMasternode . vin ;
2014-12-09 02:17:57 +01:00
dsq . time = GetTime ( ) ;
dsq . Sign ( ) ;
dsq . Relay ( ) ;
}
UpdateState ( POOL_STATUS_QUEUE ) ;
2015-03-02 00:09:33 +01:00
printf ( " Updated 2 \n " ) ;
2014-12-09 02:17:57 +01:00
vecSessionCollateral . push_back ( txCollateral ) ;
return true ;
}
2015-03-02 00:09:33 +01:00
if ( ( state ! = POOL_STATUS_IDLE & & state ! = POOL_STATUS_QUEUE ) | | sessionUsers > = GetMaxPoolTransactions ( ) ) {
if ( ( state ! = POOL_STATUS_IDLE & & state ! = POOL_STATUS_QUEUE ) ) strReason = _ ( " Incompatible mode. " ) ;
2015-02-04 14:24:56 +01:00
if ( sessionUsers > = GetMaxPoolTransactions ( ) ) strReason = _ ( " Masternode queue is full. " ) ;
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::IsCompatibleWithSession - incompatible mode, return false %d %d \n " , state ! = POOL_STATUS_ACCEPTING_ENTRIES , sessionUsers > = GetMaxPoolTransactions ( ) ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
if ( nDenom ! = sessionDenom ) {
2015-02-04 14:24:56 +01:00
strReason = _ ( " No matching denominations found for mixing. " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
2015-03-02 00:09:33 +01:00
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 " ) ;
2014-12-09 02:17:57 +01:00
sessionUsers + + ;
lastTimeChanged = GetTimeMillis ( ) ;
vecSessionCollateral . push_back ( txCollateral ) ;
return true ;
}
2014-12-28 00:45:07 +01:00
//create a nice string to show the denominations
2015-03-02 00:09:33 +01:00
void CDarksendPool : : GetDenominationsToString ( int nDenom , std : : string & strDenom ) {
2014-12-28 00:45:07 +01:00
// Function returns as follows:
//
// bit 0 - 100DRK+1 ( bit on if present )
// bit 1 - 10DRK+1
// bit 2 - 1DRK+1
2014-12-30 01:09:34 +01:00
// bit 3 - .1DRK+1
2015-01-19 22:25:03 +01:00
// bit 3 - non-denom
2014-12-28 00:45:07 +01:00
strDenom = " " ;
if ( nDenom & ( 1 < < 0 ) ) {
if ( strDenom . size ( ) > 0 ) strDenom + = " + " ;
strDenom + = " 100 " ;
}
if ( nDenom & ( 1 < < 1 ) ) {
if ( strDenom . size ( ) > 0 ) strDenom + = " + " ;
strDenom + = " 10 " ;
}
if ( nDenom & ( 1 < < 2 ) ) {
if ( strDenom . size ( ) > 0 ) strDenom + = " + " ;
strDenom + = " 1 " ;
}
if ( nDenom & ( 1 < < 3 ) ) {
if ( strDenom . size ( ) > 0 ) strDenom + = " + " ;
strDenom + = " 0.1 " ;
}
}
2014-12-09 02:17:57 +01:00
// return a bitshifted integer representing the denominations in this list
2015-03-02 00:09:33 +01:00
int CDarksendPool : : GetDenominations ( const std : : vector < CTxOut > & vout ) {
2014-12-09 02:17:57 +01:00
std : : vector < pair < int64_t , int > > denomUsed ;
// make a list of denominations, with zero uses
BOOST_FOREACH ( int64_t d , darkSendDenominations )
denomUsed . push_back ( make_pair ( d , 0 ) ) ;
// look for denominations and update uses to 1
BOOST_FOREACH ( CTxOut out , vout ) {
bool found = false ;
BOOST_FOREACH ( PAIRTYPE ( int64_t , int ) & s , denomUsed ) {
if ( out . nValue = = s . first ) {
s . second = 1 ;
found = true ;
}
}
2015-01-15 15:41:56 +01:00
if ( ! found ) return 0 ;
2014-12-09 02:17:57 +01:00
}
int denom = 0 ;
int c = 0 ;
// if the denomination is used, shift the bit on.
// then move to the next
BOOST_FOREACH ( PAIRTYPE ( int64_t , int ) & s , denomUsed )
denom | = s . second < < c + + ;
// Function returns as follows:
//
2014-12-28 00:45:07 +01:00
// bit 0 - 100DRK+1 ( bit on if present )
// bit 1 - 10DRK+1
// bit 2 - 1DRK+1
// bit 3 - .1DRK+1
2014-12-09 02:17:57 +01:00
return denom ;
}
2015-01-19 22:25:03 +01:00
2015-03-02 00:09:33 +01:00
int CDarksendPool : : GetDenominationsByAmounts ( std : : vector < int64_t > & vecAmount ) {
2014-12-09 02:17:57 +01:00
CScript e = CScript ( ) ;
std : : vector < CTxOut > vout1 ;
// Make outputs by looping through denominations, from small to large
BOOST_REVERSE_FOREACH ( int64_t v , vecAmount ) {
int nOutputs = 0 ;
CTxOut o ( v , e ) ;
vout1 . push_back ( o ) ;
nOutputs + + ;
}
return GetDenominations ( vout1 ) ;
}
2015-03-02 00:09:33 +01:00
int CDarksendPool : : GetDenominationsByAmount ( int64_t nAmount , int nDenomTarget ) {
2014-12-09 02:17:57 +01:00
CScript e = CScript ( ) ;
int64_t nValueLeft = nAmount ;
std : : vector < CTxOut > vout1 ;
// Make outputs by looping through denominations, from small to large
BOOST_REVERSE_FOREACH ( int64_t v , darkSendDenominations ) {
2014-12-30 23:42:50 +01:00
if ( nDenomTarget ! = 0 ) {
bool fAccepted = false ;
2015-01-21 14:02:59 +01:00
if ( ( nDenomTarget & ( 1 < < 0 ) ) & & v = = ( ( 100 * COIN ) + 100000 ) ) { fAccepted = true ; }
else if ( ( nDenomTarget & ( 1 < < 1 ) ) & & v = = ( ( 10 * COIN ) + 10000 ) ) { fAccepted = true ; }
else if ( ( nDenomTarget & ( 1 < < 2 ) ) & & v = = ( ( 1 * COIN ) + 1000 ) ) { fAccepted = true ; }
else if ( ( nDenomTarget & ( 1 < < 3 ) ) & & v = = ( ( .1 * COIN ) + 100 ) ) { fAccepted = true ; }
2014-12-30 23:42:50 +01:00
if ( ! fAccepted ) continue ;
}
2014-12-09 02:17:57 +01:00
int nOutputs = 0 ;
// add each output up to 10 times until it can't be added again
while ( nValueLeft - v > = 0 & & nOutputs < = 10 ) {
CTxOut o ( v , e ) ;
vout1 . push_back ( o ) ;
nValueLeft - = v ;
nOutputs + + ;
}
2015-01-21 07:09:04 +01:00
LogPrintf ( " GetDenominationsByAmount --- %d nOutputs %d \n " , v , nOutputs ) ;
2014-12-09 02:17:57 +01:00
}
//add non-denom left overs as change
if ( nValueLeft > 0 ) {
CTxOut o ( nValueLeft , e ) ;
vout1 . push_back ( o ) ;
}
return GetDenominations ( vout1 ) ;
}
bool CDarkSendSigner : : IsVinAssociatedWithPubkey ( CTxIn & vin , CPubKey & pubkey ) {
CScript payee2 ;
payee2 . SetDestination ( pubkey . GetID ( ) ) ;
CTransaction txVin ;
uint256 hash ;
if ( GetTransaction ( vin . prevout . hash , txVin , hash , true ) ) {
BOOST_FOREACH ( CTxOut out , txVin . vout ) {
if ( out . nValue = = 1000 * COIN ) {
if ( out . scriptPubKey = = payee2 ) return true ;
}
}
}
return false ;
}
bool CDarkSendSigner : : SetKey ( std : : string strSecret , std : : string & errorMessage , CKey & key , CPubKey & pubkey ) {
CBitcoinSecret vchSecret ;
bool fGood = vchSecret . SetString ( strSecret ) ;
if ( ! fGood ) {
2015-02-04 14:24:56 +01:00
errorMessage = _ ( " Invalid private key. " ) ;
2014-12-09 02:17:57 +01:00
return false ;
2014-12-25 20:21:35 +01:00
}
2014-12-09 02:17:57 +01:00
key = vchSecret . GetKey ( ) ;
pubkey = key . GetPubKey ( ) ;
return true ;
}
bool CDarkSendSigner : : SignMessage ( std : : string strMessage , std : : string & errorMessage , vector < unsigned char > & vchSig , CKey key )
{
CHashWriter ss ( SER_GETHASH , 0 ) ;
ss < < strMessageMagic ;
ss < < strMessage ;
if ( ! key . SignCompact ( ss . GetHash ( ) , vchSig ) ) {
2015-02-04 14:24:56 +01:00
errorMessage = _ ( " Signing failed. " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
return true ;
}
bool CDarkSendSigner : : VerifyMessage ( CPubKey pubkey , vector < unsigned char > & vchSig , std : : string strMessage , std : : string & errorMessage )
{
CHashWriter ss ( SER_GETHASH , 0 ) ;
ss < < strMessageMagic ;
ss < < strMessage ;
CPubKey pubkey2 ;
if ( ! pubkey2 . RecoverCompact ( ss . GetHash ( ) , vchSig ) ) {
2015-02-04 14:24:56 +01:00
errorMessage = _ ( " Error recovering public key. " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
2015-01-25 22:18:26 +01:00
if ( fDebug & & pubkey2 . GetID ( ) ! = pubkey . GetID ( ) )
LogPrintf ( " CDarkSendSigner::VerifyMessage -- keys don't match: %s %s " , pubkey2 . GetID ( ) . ToString ( ) , pubkey . GetID ( ) . ToString ( ) ) ;
2014-12-09 02:17:57 +01:00
return ( pubkey2 . GetID ( ) = = pubkey . GetID ( ) ) ;
}
bool CDarksendQueue : : Sign ( )
{
if ( ! fMasterNode ) return false ;
2014-12-25 20:21:35 +01:00
std : : string strMessage = vin . ToString ( ) + boost : : lexical_cast < std : : string > ( nDenom ) + boost : : lexical_cast < std : : string > ( time ) + boost : : lexical_cast < std : : string > ( ready ) ;
2014-12-09 02:17:57 +01:00
CKey key2 ;
CPubKey pubkey2 ;
std : : string errorMessage = " " ;
if ( ! darkSendSigner . SetKey ( strMasterNodePrivKey , errorMessage , key2 , pubkey2 ) )
{
2015-01-18 16:28:16 +01:00
LogPrintf ( " CDarksendQueue():Relay - ERROR: Invalid masternodeprivkey: '%s' \n " , errorMessage . c_str ( ) ) ;
return false ;
2014-12-09 02:17:57 +01:00
}
if ( ! darkSendSigner . SignMessage ( strMessage , errorMessage , vchSig , key2 ) ) {
LogPrintf ( " CDarksendQueue():Relay - Sign message failed " ) ;
return false ;
}
if ( ! darkSendSigner . VerifyMessage ( pubkey2 , vchSig , strMessage , errorMessage ) ) {
LogPrintf ( " CDarksendQueue():Relay - Verify message failed " ) ;
return false ;
}
2015-03-02 00:09:33 +01:00
// -- second signature, for proving access to the anonymous relay system
nBlockHeight = chainActive . Tip ( ) - > nHeight ; //sign with our current blockheight
strMessage = boost : : lexical_cast < std : : string > ( 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 ;
}
2014-12-09 02:17:57 +01:00
return true ;
}
bool CDarksendQueue : : Relay ( )
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes ) {
// always relay to everyone
pnode - > PushMessage ( " dsq " , ( * this ) ) ;
}
return true ;
}
bool CDarksendQueue : : CheckSignature ( )
{
2015-02-25 12:54:03 +01:00
CMasternode * pmn = mnodeman . Find ( vin ) ;
2014-12-09 02:17:57 +01:00
2015-02-25 12:54:03 +01:00
if ( pmn ! = NULL )
2015-02-23 21:01:21 +01:00
{
std : : string strMessage = vin . ToString ( ) + boost : : lexical_cast < std : : string > ( nDenom ) + boost : : lexical_cast < std : : string > ( time ) + boost : : lexical_cast < std : : string > ( ready ) ;
2014-12-09 02:17:57 +01:00
2015-02-23 21:01:21 +01:00
std : : string errorMessage = " " ;
2015-02-25 12:54:03 +01:00
if ( ! darkSendSigner . VerifyMessage ( pmn - > pubkey2 , vchSig , strMessage , errorMessage ) ) {
2015-02-23 21:01:21 +01:00
return error ( " CDarksendQueue::CheckSignature() - Got bad masternode address signature % s \ n " , vin.ToString().c_str()) ;
2014-12-09 02:17:57 +01:00
}
2015-02-23 21:01:21 +01:00
2015-03-02 00:09:33 +01:00
// -- second signature, for proving access to the anonymous relay system
if ( ready )
{
strMessage = boost : : lexical_cast < std : : string > ( nBlockHeight ) ;
if ( ! darkSendSigner . VerifyMessage ( pmn - > pubkey2 , vchRelaySig , strMessage , errorMessage ) ) {
LogPrintf ( " CDarksendQueue():CheckSignature - Verify message failed " ) ;
return false ;
}
}
2015-02-23 21:01:21 +01:00
return true ;
2014-12-09 02:17:57 +01:00
}
return false ;
}
2015-03-02 00:09:33 +01:00
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 < CTxIn > & 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 < CTxIn > & vin , std : : vector < CTxOut > & 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 < CTxIn > & vin , const int64_t & nAmount , const CTransaction & txCollateral , const std : : vector < CTxOut > & 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 ;
}
2015-02-09 20:28:29 +01:00
//TODO: Rename/move to core
2014-12-09 02:17:57 +01:00
void ThreadCheckDarkSendPool ( )
{
2015-01-18 16:28:16 +01:00
if ( fLiteMode ) return ; //disable all darksend/masternode related functionality
2014-12-09 02:17:57 +01:00
// Make this thread recognisable as the wallet flushing thread
2015-02-04 14:24:56 +01:00
RenameThread ( " darkcoin-darksend " ) ;
2014-12-09 02:17:57 +01:00
unsigned int c = 0 ;
2014-12-06 20:41:53 +01:00
std : : string errorMessage ;
2014-12-09 02:17:57 +01:00
while ( true )
{
c + + ;
MilliSleep ( 1000 ) ;
//LogPrintf("ThreadCheckDarkSendPool::check timeout\n");
2015-03-04 19:17:30 +01:00
2015-03-02 00:09:33 +01:00
if ( c % 10 = = 0 ) darkSendPool . Check ( ) ;
2014-12-09 02:17:57 +01:00
darkSendPool . CheckTimeout ( ) ;
2015-03-02 00:09:33 +01:00
darkSendPool . CheckForCompleteQueue ( ) ;
2014-12-25 20:21:35 +01:00
2015-02-26 00:21:28 +01:00
if ( c % 60 = = 0 )
{
LOCK ( cs_main ) ;
/*
cs_main is required for doing CMasternode . Check because something
is modifying the coins view without a mempool lock . It causes
segfaults from this code without the cs_main lock .
*/
mnodeman . CheckAndRemove ( ) ;
2015-03-02 00:09:33 +01:00
mnodeman . ProcessMasternodeConnections ( ) ;
2015-02-23 21:07:37 +01:00
masternodePayments . CleanPaymentList ( ) ;
CleanTransactionLocksList ( ) ;
}
2015-01-23 15:48:39 +01:00
2015-02-23 21:07:37 +01:00
if ( c % MASTERNODE_PING_SECONDS = = 0 ) activeMasternode . ManageStatus ( ) ;
2014-12-09 02:17:57 +01:00
2015-02-23 21:07:37 +01:00
if ( c % MASTERNODES_DUMP_SECONDS = = 0 ) DumpMasternodes ( ) ;
2014-12-09 02:17:57 +01:00
2015-01-22 01:04:52 +01:00
//try to sync the masternode list and payment list every 5 seconds from at least 3 nodes
2015-01-26 19:03:36 +01:00
if ( c % 5 = = 0 & & RequestedMasterNodeList < 3 ) {
2014-12-09 02:17:57 +01:00
bool fIsInitialDownload = IsInitialBlockDownload ( ) ;
if ( ! fIsInitialDownload ) {
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
{
2015-02-26 18:09:39 +01:00
if ( pnode - > nVersion > = MIN_POOL_PEER_PROTO_VERSION ) {
2014-12-09 02:17:57 +01:00
//keep track of who we've asked for the list
if ( pnode - > HasFulfilledRequest ( " mnsync " ) ) continue ;
pnode - > FulfilledRequest ( " mnsync " ) ;
LogPrintf ( " Successfully synced, asking for Masternode list and payment list \n " ) ;
2014-12-25 20:21:35 +01:00
2015-02-24 11:39:29 +01:00
//request full mn list only if masternodes.dat was updated quite a long time ago
2015-02-26 00:21:28 +01:00
mnodeman . DsegUpdate ( pnode ) ;
2015-02-23 21:01:21 +01:00
2014-12-09 02:17:57 +01:00
pnode - > PushMessage ( " mnget " ) ; //sync payees
2015-02-09 20:28:29 +01:00
pnode - > PushMessage ( " getsporks " ) ; //get current network sporks
2014-12-09 02:17:57 +01:00
RequestedMasterNodeList + + ;
}
}
}
}
if ( c % 60 = = 0 ) {
//if we've used 1/5 of the masternode list, then clear the list.
2015-02-23 21:01:21 +01:00
if ( ( int ) vecMasternodesUsed . size ( ) > ( int ) mnodeman . size ( ) / 5 )
2014-12-09 02:17:57 +01:00
vecMasternodesUsed . clear ( ) ;
}
//auto denom every 2.5 minutes (liquidity provides try less often)
if ( c % 60 * ( nLiquidityProvider + 1 ) = = 0 ) {
if ( nLiquidityProvider ! = 0 ) {
int nRand = rand ( ) % ( 101 + nLiquidityProvider ) ;
2014-12-25 20:21:35 +01:00
//about 1/100 chance of starting over after 4 rounds.
2014-12-09 02:17:57 +01:00
if ( nRand = = 50 + nLiquidityProvider & & pwalletMain - > GetAverageAnonymizedRounds ( ) > 8 ) {
darkSendPool . SendRandomPaymentToSelf ( ) ;
int nLeftToAnon = ( ( pwalletMain - > GetBalance ( ) - pwalletMain - > GetAnonymizedBalance ( ) ) / COIN ) - 3 ;
if ( nLeftToAnon > 999 ) nLeftToAnon = 999 ;
nAnonymizeDarkcoinAmount = ( rand ( ) % nLeftToAnon ) + 3 ;
} else {
darkSendPool . DoAutomaticDenominating ( ) ;
}
} else {
darkSendPool . DoAutomaticDenominating ( ) ;
}
}
}
}
2015-03-02 00:09:33 +01:00