2015-03-18 00:06:58 +01:00
// Copyright (c) 2014-2015 The Dash developers
2015-02-04 14:24:56 +01:00
// 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"
2015-04-03 00:51:08 +02:00
# include "script/sign.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>
2015-04-03 00:51:08 +02:00
# include <openssl/rand.h>
2014-12-09 02:17:57 +01:00
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
2015-03-08 15:49:04 +01:00
// The main object for accessing Darksend
2015-03-02 00:09:33 +01:00
CDarksendPool darkSendPool ;
2015-03-08 15:49:04 +01:00
// A helper object for signing messages from Masternodes
2014-12-09 02:17:57 +01:00
CDarkSendSigner darkSendSigner ;
2015-03-08 15:49:04 +01:00
// The current Darksends in progress on the network
2014-12-09 02:17:57 +01:00
std : : vector < CDarksendQueue > vecDarksendQueue ;
2015-03-08 15:49:04 +01:00
// Keep track of the used Masternodes
2014-12-09 02:17:57 +01:00
std : : vector < CTxIn > vecMasternodesUsed ;
2015-03-05 08:49:50 +01:00
// Keep track of the scanning errors I've seen
2014-12-09 02:17:57 +01:00
map < uint256 , CDarksendBroadcastTx > mapDarksendBroadcastTxes ;
2015-03-05 09:10:15 +01:00
// Keep track of the active Masternode
2014-12-09 02:17:57 +01:00
CActiveMasternode activeMasternode ;
2015-03-05 08:49:50 +01:00
// Count peers we've requested the list from
2015-05-04 17:04:09 +02:00
int RequestedMasternodeAssets = 0 ;
bool IsSyncingMasternodeAssets ( ) {
return RequestedMasternodeAssets ! = MASTERNODE_LIST_SYNCED ;
}
2014-12-09 02:17:57 +01:00
2015-03-19 15:15:08 +01:00
/* *** BEGIN DARKSEND MAGIC - DASH **********
2015-03-18 00:06:58 +01:00
Copyright ( c ) 2014 - 2015 , Dash Developers
2015-03-20 15:45:30 +01:00
eduffield - evan @ dashpay . io
udjinm6 - udjinm6 @ dashpay . 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-03-05 09:10:15 +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-05 08:49:50 +01:00
if ( strCommand = = " dsa " ) { //Darksend Accept Into Pool
2015-01-19 22:25:03 +01:00
2015-04-15 00:40:28 +02:00
int errorID ;
2015-02-26 18:09:39 +01:00
if ( pfrom - > nVersion < MIN_POOL_PEER_PROTO_VERSION ) {
2015-04-15 00:40:28 +02:00
errorID = ERR_VERSION ;
2014-12-09 02:17:57 +01:00
LogPrintf ( " dsa -- incompatible version! \n " ) ;
2015-04-15 00:40:28 +02:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
2014-12-09 02:17:57 +01:00
return ;
}
if ( ! fMasterNode ) {
2015-04-15 00:40:28 +02:00
errorID = ERR_NOT_A_MN ;
2015-03-05 09:10:15 +01:00
LogPrintf ( " dsa -- not a Masternode! \n " ) ;
2015-04-15 00:40:28 +02:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
2014-12-09 02:17:57 +01:00
return ;
}
int nDenom ;
CTransaction txCollateral ;
vRecv > > nDenom > > txCollateral ;
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-04-15 00:40:28 +02:00
errorID = ERR_MN_LIST ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
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-06 18:25:48 +01:00
pmn - > nLastDsq + mnodeman . CountMasternodesAboveProtocol ( MIN_POOL_PEER_PROTO_VERSION ) / 5 > mnodeman . nDsqCount ) {
2015-03-13 16:53:12 +01:00
LogPrintf ( " dsa -- last dsq too recent, must wait. %s \n " , pfrom - > addr . ToString ( ) . c_str ( ) ) ;
2015-04-15 00:40:28 +02:00
errorID = ERR_RECENT ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
2014-12-09 02:17:57 +01:00
return ;
}
}
2015-04-15 00:40:28 +02:00
if ( ! IsCompatibleWithSession ( nDenom , txCollateral , errorID ) )
2014-12-09 02:17:57 +01:00
{
LogPrintf ( " dsa -- not compatible with existing transactions! \n " ) ;
2015-04-15 00:40:28 +02:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
2014-12-09 02:17:57 +01:00
return ;
} else {
LogPrintf ( " dsa -- is compatible, please submit! \n " ) ;
2015-04-15 00:40:28 +02:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_ACCEPTED , errorID ) ;
2014-12-09 02:17:57 +01:00
return ;
}
2015-03-02 00:09:33 +01:00
2015-03-05 08:49:50 +01:00
} else if ( strCommand = = " dsq " ) { //Darksend Queue
2015-03-22 04:26:48 +01:00
TRY_LOCK ( cs_darksend , lockRecv ) ;
if ( ! lockRecv ) return ;
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 ) {
2015-03-05 09:10:15 +01:00
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 ) {
2015-03-05 08:49:50 +01:00
if ( fDebug ) LogPrintf ( " Darksend queue is ready - %s \n " , addr . ToString ( ) . c_str ( ) ) ;
2015-03-02 00:09:33 +01:00
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-06 18:25:48 +01:00
if ( fDebug ) LogPrintf ( " dsq last %d last2 %d count %d \n " , pmn - > nLastDsq , pmn - > nLastDsq + mnodeman . size ( ) / 5 , mnodeman . 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-06 18:25:48 +01:00
pmn - > nLastDsq + mnodeman . CountMasternodesAboveProtocol ( MIN_POOL_PEER_PROTO_VERSION ) / 5 > mnodeman . nDsqCount ) {
2015-03-05 09:10:15 +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-06 18:25:48 +01:00
mnodeman . nDsqCount + + ;
pmn - > nLastDsq = mnodeman . nDsqCount ;
2015-02-25 12:54:03 +01:00
pmn - > allowFreeTx = true ;
2014-12-09 02:17:57 +01:00
2015-03-05 08:49:50 +01:00
if ( fDebug ) LogPrintf ( " dsq - new Darksend queue object - %s \n " , addr . ToString ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
vecDarksendQueue . push_back ( dsq ) ;
dsq . Relay ( ) ;
dsq . time = GetTime ( ) ;
}
2015-04-06 08:52:37 +02:00
} else if ( strCommand = = " dsi " ) { //DarkSend vIn
2015-06-24 21:42:01 +02:00
int errorID ;
2015-06-24 18:23:22 +02: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
LogPrintf ( " dsi -- incompatible version! \n " ) ;
2015-04-15 00:40:28 +02:00
errorID = ERR_VERSION ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
2014-12-09 02:17:57 +01:00
return ;
}
if ( ! fMasterNode ) {
2015-03-05 09:10:15 +01:00
LogPrintf ( " dsi -- not a Masternode! \n " ) ;
2015-04-15 00:40:28 +02:00
errorID = ERR_NOT_A_MN ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
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-04-15 00:40:28 +02:00
errorID = ERR_SESSION ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
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-04-15 00:40:28 +02:00
errorID = ERR_EXISTING_TX ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
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 ;
2015-04-03 00:51:08 +02:00
CMutableTransaction tx ;
2014-12-09 02:17:57 +01:00
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-04-15 00:40:28 +02:00
errorID = ERR_NON_STANDARD_PUBKEY ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
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-04-15 00:40:28 +02:00
errorID = ERR_INVALID_SCRIPT ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
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 ) {
2015-03-05 08:49:50 +01:00
LogPrintf ( " dsi -- more than Darksend pool max! %s \n " , tx . ToString ( ) . c_str ( ) ) ;
2015-04-15 00:40:28 +02:00
errorID = ERR_MAXIMUM ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
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-04-15 00:40:28 +02:00
errorID = ERR_FEES ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
2014-12-09 02:17:57 +01:00
return ;
}
} else {
LogPrintf ( " dsi -- missing input tx! %s \n " , tx . ToString ( ) . c_str ( ) ) ;
2015-04-15 00:40:28 +02:00
errorID = ERR_MISSING_TX ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
2014-12-09 02:17:57 +01:00
return ;
}
2015-06-23 06:12:24 +02:00
if ( ! AcceptableInputs ( mempool , state , CTransaction ( tx ) , false , NULL , false , true ) ) {
2014-12-09 02:17:57 +01:00
LogPrintf ( " dsi -- transaction not valid! \n " ) ;
2015-04-15 00:40:28 +02:00
errorID = ERR_INVALID_TX ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
2014-12-09 02:17:57 +01:00
return ;
}
}
2015-04-15 00:40:28 +02:00
if ( AddEntry ( in , nAmount , txCollateral , out , errorID ) ) {
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_ACCEPTED , errorID ) ;
2015-03-02 00:09:33 +01:00
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-04-15 00:40:28 +02:00
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
2014-12-09 02:17:57 +01:00
}
2015-03-04 19:17:30 +01:00
2015-03-05 08:49:50 +01:00
} else if ( strCommand = = " dssu " ) { //Darksend status update
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 ) {
2015-03-05 09:10:15 +01:00
//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 ;
2015-04-15 00:40:28 +02:00
int errorID ;
vRecv > > sessionIDMessage > > state > > entriesCount > > accepted > > errorID ;
2014-12-09 02:17:57 +01:00
2015-04-15 00:40:28 +02:00
if ( fDebug ) LogPrintf ( " dssu - state: %i entriesCount: %i accepted: %i error: %s \n " , state , entriesCount , accepted , GetMessageByID ( errorID ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
if ( ( accepted ! = 1 & & accepted ! = 0 ) & & sessionID ! = sessionIDMessage ) {
2015-03-05 08:49:50 +01:00
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-04-15 00:40:28 +02:00
StatusUpdate ( state , entriesCount , accepted , errorID , sessionIDMessage ) ;
2014-12-09 02:17:57 +01:00
2015-03-05 08:49:50 +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 ;
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-04-06 17:39:48 +02:00
darkSendPool . Check ( ) ;
RelayStatus ( darkSendPool . sessionID , darkSendPool . GetState ( ) , darkSendPool . GetEntriesCount ( ) , MASTERNODE_RESET ) ;
2015-03-02 00:09:33 +01:00
}
2015-03-05 08:49:50 +01:00
} else if ( strCommand = = " dsf " ) { //Darksend Final tx
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 ) {
2015-03-05 09:10:15 +01:00
//LogPrintf("dsc - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString().c_str(), pfrom->addr.ToString().c_str());
2015-03-02 00:09:33 +01:00
return ;
}
int sessionIDMessage ;
CTransaction txNew ;
vRecv > > sessionIDMessage > > txNew ;
if ( sessionID ! = sessionIDMessage ) {
2015-03-05 08:49:50 +01:00
if ( fDebug ) LogPrintf ( " dsf - message doesn't match current Darksend session %d %d \n " , sessionID , sessionIDMessage ) ;
2015-03-02 00:09:33 +01:00
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-05 08:49:50 +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 ) {
2015-03-05 09:10:15 +01:00
//LogPrintf("dsc - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString().c_str(), pfrom->addr.ToString().c_str());
2015-03-02 00:09:33 +01:00
return ;
}
int sessionIDMessage ;
bool error ;
2015-06-19 03:42:25 +02:00
int errorID ;
vRecv > > sessionIDMessage > > error > > errorID ;
2015-03-02 00:09:33 +01:00
if ( sessionID ! = sessionIDMessage ) {
2015-03-05 08:49:50 +01:00
if ( fDebug ) LogPrintf ( " dsc - message doesn't match current Darksend session %d %d \n " , darkSendPool . sessionID , sessionIDMessage ) ;
2015-03-02 00:09:33 +01:00
return ;
2014-12-09 02:17:57 +01:00
}
2015-03-02 00:09:33 +01:00
2015-06-19 03:42:25 +02:00
darkSendPool . CompletedTransaction ( error , errorID ) ;
2014-12-09 02:17:57 +01:00
}
}
int randomizeList ( int i ) { return std : : rand ( ) % i ; }
2015-03-05 08:49:50 +01:00
// Recursively determine the rounds of a given input (How deep is the Darksend chain for a given input)
2015-07-07 09:16:01 +02:00
int GetRealInputDarksendRounds ( CTxIn in , int rounds )
2014-12-09 02:17:57 +01:00
{
2015-04-03 00:51:08 +02:00
static std : : map < uint256 , CMutableTransaction > mDenomWtxes ;
2015-02-12 14:58:12 +01:00
2015-07-07 09:16:01 +02:00
if ( rounds > = 16 ) return 15 ; // 16 rounds max
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-04-03 00:51:08 +02:00
std : : map < uint256 , CMutableTransaction > : : const_iterator mdwi = mDenomWtxes . find ( hash ) ;
2015-02-12 14:58:12 +01:00
// not known yet, let's add it
if ( mdwi = = mDenomWtxes . end ( ) )
{
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds INSERTING %s \n " , hash . ToString ( ) ) ;
2015-04-03 00:51:08 +02:00
mDenomWtxes [ hash ] = CMutableTransaction ( wtx ) ;
2015-02-12 14:58:12 +01:00
}
// found and it's not an initial value, just return it
else if ( mDenomWtxes [ hash ] . vout [ nout ] . nRounds ! = - 10 )
{
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 ( ) )
{
2015-04-03 00:51:08 +02:00
// should never actually hit this
2015-07-07 09:16:01 +02:00
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , - 4 ) ;
2015-04-03 00:51:08 +02:00
return - 4 ;
2015-02-12 14:58:12 +01:00
}
2014-12-09 02:17:57 +01:00
2015-02-12 14:58:12 +01:00
if ( pwalletMain - > IsCollateralAmount ( wtx . vout [ nout ] . nValue ) )
{
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = - 3 ;
2015-07-07 09:16:01 +02:00
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-02-12 14:58:12 +01:00
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
if ( /*rounds == 0 && */ ! pwalletMain - > IsDenominatedAmount ( wtx . vout [ nout ] . nValue ) ) //NOT DENOM
{
mDenomWtxes [ hash ] . vout [ nout ] . nRounds = - 2 ;
2015-07-07 09:16:01 +02:00
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-02-12 14:58:12 +01:00
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 ;
2015-07-07 09:16:01 +02:00
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-02-12 14:58:12 +01:00
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 ) )
{
2015-07-07 09:16:01 +02:00
int n = GetRealInputDarksendRounds ( 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
2015-07-07 09:16:01 +02:00
? ( nShortest > = 15 ? 16 : nShortest + 1 ) // good, we a +1 to the shortest one but only 16 rounds max allowed
2015-02-12 14:58:12 +01:00
: 0 ; // too bad, we are the fist one in that chain
2015-07-07 09:16:01 +02:00
if ( fDebug ) LogPrintf ( " GetInputDarksendRounds UPDATED %s %3d %3d \n " , hash . ToString ( ) , nout , mDenomWtxes [ hash ] . vout [ nout ] . nRounds ) ;
2015-02-12 14:58:12 +01:00
return mDenomWtxes [ hash ] . vout [ nout ] . nRounds ;
2014-12-09 02:17:57 +01:00
}
return rounds - 1 ;
}
2015-07-07 09:16:01 +02:00
// respect current settings
int GetInputDarksendRounds ( CTxIn in ) {
int realDarksendRounds = GetRealInputDarksendRounds ( in , 0 ) ;
return realDarksendRounds > nDarksendRounds ? nDarksendRounds : realDarksendRounds ;
}
2015-03-02 00:09:33 +01:00
void CDarksendPool : : Reset ( ) {
2014-12-28 15:46:39 +01:00
cachedLastSuccess = 0 ;
2015-05-30 05:46:29 +02:00
lastNewBlock = 0 ;
txCollateral = CMutableTransaction ( ) ;
2014-12-28 15:46:39 +01:00
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
state = POOL_STATUS_IDLE ;
2014-12-09 02:17:57 +01:00
lastTimeChanged = GetTimeMillis ( ) ;
entriesCount = 0 ;
lastEntryAccepted = 0 ;
countEntriesAccepted = 0 ;
sessionUsers = 0 ;
sessionDenom = 0 ;
sessionFoundMasternode = false ;
vecSessionCollateral . clear ( ) ;
if ( clearEverything ) {
myEntries . clear ( ) ;
2015-03-18 17:41:30 +01:00
sessionID = 0 ;
2014-12-09 02:17:57 +01:00
}
// -- 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-05 08:49:50 +01:00
LogPrintf ( " CDarksendPool::SetCollateralAddress - Invalid Darksend collateral address \n " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
2015-04-03 00:51:08 +02:00
collateralPubKey = GetScriptForDestination ( address . Get ( ) ) ;
2014-12-09 02:17:57 +01:00
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 ( ) ;
}
2015-06-24 18:08:14 +02:00
std : : string CDarksendPool : : GetStatus ( )
{
static int showingDarkSendMessage = 0 ;
showingDarkSendMessage + = 3 ;
std : : string suffix = " " ;
if ( chainActive . Tip ( ) - > nHeight - cachedLastSuccess < minBlockSpacing ) {
return strAutoDenomResult ;
}
switch ( state ) {
case POOL_STATUS_IDLE :
return _ ( " Darksend is idle. " ) ;
case POOL_STATUS_ACCEPTING_ENTRIES :
if ( entriesCount = = 0 ) {
showingDarkSendMessage = 0 ;
return strAutoDenomResult ;
} else if ( lastEntryAccepted = = 1 ) {
if ( showingDarkSendMessage % 10 > 8 ) {
lastEntryAccepted = 0 ;
showingDarkSendMessage = 0 ;
}
return _ ( " Darksend request complete: " ) + " " + _ ( " Your transaction was accepted into the pool! " ) ;
} else {
std : : string suffix = " " ;
if ( showingDarkSendMessage % 70 < = 40 ) return strprintf ( _ ( " Submitted following entries to masternode: %u / %d " ) , entriesCount , GetMaxPoolTransactions ( ) ) ;
else if ( showingDarkSendMessage % 70 < = 50 ) suffix = " . " ;
else if ( showingDarkSendMessage % 70 < = 60 ) suffix = " .. " ;
else if ( showingDarkSendMessage % 70 < = 70 ) suffix = " ... " ;
return strprintf ( _ ( " Submitted to masternode, waiting for more entries ( %u / %d ) % s " ), entriesCount, GetMaxPoolTransactions(), suffix) ;
}
case POOL_STATUS_SIGNING :
if ( showingDarkSendMessage % 70 < = 40 ) return _ ( " Found enough users, signing ... " ) ;
else if ( showingDarkSendMessage % 70 < = 50 ) suffix = " . " ;
else if ( showingDarkSendMessage % 70 < = 60 ) suffix = " .. " ;
else if ( showingDarkSendMessage % 70 < = 70 ) suffix = " ... " ;
return strprintf ( _ ( " Found enough users, signing ( waiting %s ) " ), suffix) ;
case POOL_STATUS_TRANSMISSION :
return _ ( " Transmitting final transaction. " ) ;
case POOL_STATUS_FINALIZE_TRANSACTION :
return _ ( " Finalizing transaction. " ) ;
case POOL_STATUS_ERROR :
return _ ( " Darksend request incomplete: " ) + " " + lastMessage + " " + _ ( " Will retry... " ) ;
case POOL_STATUS_SUCCESS :
return _ ( " Darksend request complete: " ) + " " + lastMessage ;
case POOL_STATUS_QUEUE :
if ( showingDarkSendMessage % 70 < = 30 ) suffix = " . " ;
else if ( showingDarkSendMessage % 70 < = 50 ) suffix = " .. " ;
else if ( showingDarkSendMessage % 70 < = 70 ) suffix = " ... " ;
return strprintf ( _ ( " Submitted to masternode, waiting in queue %s " ) , suffix ) ; ;
default :
return strprintf ( _ ( " Unknown state: id = %u " ) , state ) ;
}
}
2014-12-09 02:17:57 +01:00
//
2015-03-05 09:10:15 +01:00
// 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-13 16:53:12 +01:00
if ( fDebug & & fMasterNode ) 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-04-06 08:52:37 +02:00
if ( state = = POOL_STATUS_ACCEPTING_ENTRIES & & ( int ) entries . size ( ) > = GetMaxPoolTransactions ( ) )
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 ) ;
}
// 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 ) {
2015-04-03 00:51:08 +02:00
CMutableTransaction txNew ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
// make our new transaction
2015-04-06 08:52:37 +02:00
for ( unsigned int i = 0 ; i < entries . size ( ) ; i + + ) {
BOOST_FOREACH ( const CTxOut & v , entries [ i ] . vout )
txNew . vout . push_back ( v ) ;
2015-03-02 00:09:33 +01:00
2015-04-06 08:52:37 +02:00
BOOST_FOREACH ( const CTxDSIn & s , entries [ i ] . sev )
txNew . vin . push_back ( s ) ;
}
2015-03-02 00:09:33 +01:00
2015-04-06 08:52:37 +02:00
// shuffle the outputs for improved anonymity
std : : random_shuffle ( txNew . vin . begin ( ) , txNew . vin . end ( ) , randomizeList ) ;
std : : random_shuffle ( txNew . vout . begin ( ) , txNew . vout . end ( ) , randomizeList ) ;
2015-03-02 00:09:33 +01:00
2014-12-09 02:17:57 +01:00
if ( fDebug ) LogPrintf ( " Transaction 1: %s \n " , txNew . ToString ( ) . c_str ( ) ) ;
2015-03-06 23:17:51 +01:00
finalTransaction = txNew ;
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
}
}
// 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 ) ;
2015-06-24 18:25:43 +02:00
if ( fMasterNode ) RelayStatus ( sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_RESET ) ;
2015-03-02 00:09:33 +01:00
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
2015-06-23 22:44:20 +02:00
if ( ! txNew . AcceptToMemoryPool ( false , true , true ) )
2015-03-02 00:09:33 +01:00
{
2015-04-06 08:52:37 +02:00
LogPrintf ( " CDarksendPool::Check() - CommitTransaction : Error: Transaction not valid \n " ) ;
SetNull ( ) ;
pwalletMain - > Lock ( ) ;
2014-12-09 02:17:57 +01:00
2015-04-06 17:39:48 +02:00
// not much we can do in this case
2015-03-02 00:09:33 +01:00
UpdateState ( POOL_STATUS_ACCEPTING_ENTRIES ) ;
2015-04-15 00:40:28 +02:00
RelayCompletedTransaction ( sessionID , true , ERR_INVALID_TX ) ;
2015-03-02 00:09:33 +01:00
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 ) )
{
2015-03-05 09:10:15 +01:00
LogPrintf ( " CDarksendPool::Check() - ERROR: Invalid Masternodeprivkey: '%s' \n " , strError . c_str ( ) ) ;
2015-03-02 00:09:33 +01:00
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
2015-04-15 00:40:28 +02:00
RelayCompletedTransaction ( sessionID , false , MSG_SUCCESS ) ;
2015-03-02 00:09:33 +01:00
// Randomly charge clients
ChargeRandomFees ( ) ;
// Reset
if ( fDebug ) LogPrintf ( " CDarksendPool::Check() -- COMPLETED -- RESETTING \n " ) ;
SetNull ( true ) ;
UnlockCoins ( ) ;
2015-06-24 18:25:43 +02:00
if ( fMasterNode ) RelayStatus ( sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_RESET ) ;
2015-03-02 00:09:33 +01:00
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.
2015-03-05 08:49:50 +01:00
// 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
//
2015-03-05 09:10:15 +01:00
// How does this work? Messages to Masternodes come in via "dsi", these require a valid collateral
// 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?
2015-04-03 00:51:08 +02:00
if ( offences > = Params ( ) . PoolMaxTransactions ( ) - 1 & & r > 33 ) return ;
2014-12-09 02:17:57 +01:00
//everyone is an offender? That's not right
2015-04-03 00:51:08 +02:00
if ( offences > = Params ( ) . PoolMaxTransactions ( ) ) return ;
2014-12-09 02:17:57 +01:00
//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
2015-03-06 23:17:51 +01:00
if ( ! wtxCollateral . AcceptToMemoryPool ( false ) )
2014-12-09 02:17:57 +01:00
{
// 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 :
2015-03-05 08:49:50 +01:00
Being that Darksend has " no fees " we need to have some kind of cost associated
2015-01-02 19:45:40 +01:00
with using it to stop abuse . Otherwise it could serve as an attack vector and
2015-03-18 00:06:58 +01:00
allow endless transaction that would bloat Dash 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 ( ) ;
}
}
}
}
//
2015-03-05 08:49:50 +01:00
// Check for various timeouts (queue objects, Darksend, etc)
2014-12-09 02:17:57 +01:00
//
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 ) {
2015-06-24 18:08:14 +02:00
switch ( state ) {
case POOL_STATUS_TRANSMISSION :
if ( fDebug ) LogPrintf ( " CDarksendPool::CheckTimeout() -- Session complete -- Running Check() \n " ) ;
Check ( ) ;
break ;
case POOL_STATUS_ERROR :
if ( fDebug ) LogPrintf ( " CDarksendPool::CheckTimeout() -- Pool error -- Running Check() \n " ) ;
Check ( ) ;
break ;
case POOL_STATUS_SUCCESS :
if ( fDebug ) LogPrintf ( " CDarksendPool::CheckTimeout() -- Pool success -- Running Check() \n " ) ;
Check ( ) ;
break ;
2014-12-25 20:21:35 +01:00
}
2014-12-09 02:17:57 +01:00
}
2015-03-05 08:49:50 +01:00
// check Darksend queue objects for timeouts
2014-12-09 02:17:57 +01:00
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 ;
2015-03-05 09:10:15 +01:00
// if it's a Masternode, the entries are stored in "entries", otherwise they're stored in myEntries
2014-12-09 02:17:57 +01:00
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-06-24 18:25:43 +02:00
RelayStatus ( sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_RESET ) ;
2014-12-09 02:17:57 +01:00
}
break ;
}
c + + ;
}
if ( GetTimeMillis ( ) - lastTimeChanged > = ( DARKSEND_QUEUE_TIMEOUT * 1000 ) + addLagTime ) {
lastTimeChanged = GetTimeMillis ( ) ;
2015-05-30 05:46:29 +02:00
UnlockCoins ( ) ;
2015-04-06 17:39:48 +02:00
SetNull ( true ) ;
2014-12-09 02:17:57 +01:00
}
} 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-04-06 17:39:48 +02:00
lastMessage = _ ( " Session timed out, 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 ( 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. " ) ;
}
}
//
// 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 ( ) ) {
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 ) {
2015-04-03 00:51:08 +02:00
CMutableTransaction txNew ;
2014-12-09 02:17:57 +01:00
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 ( ) ) ;
2015-04-03 00:51:08 +02:00
if ( ! VerifyScript ( txNew . vin [ n ] . scriptSig , sigPubKey , SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC , MutableTransactionSignatureChecker ( & txNew , n ) ) ) {
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 ;
2015-04-03 00:51:08 +02:00
if ( ! AcceptableInputs ( mempool , state , txCollateral , true , NULL ) ) {
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-04-15 00:40:28 +02:00
bool CDarksendPool : : AddEntry ( const std : : vector < CTxIn > & newInput , const int64_t & nAmount , const CTransaction & txCollateral , const std : : vector < CTxOut > & newOutput , int & errorID ) {
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-04-15 00:40:28 +02:00
errorID = ERR_INVALID_INPUT ;
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-04-15 00:40:28 +02:00
errorID = ERR_INVALID_COLLATERAL ;
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-04-15 00:40:28 +02:00
errorID = ERR_ENTRIES_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-04-15 00:40:28 +02:00
errorID = ERR_ALREADY_HAVE ;
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 ( ) ) ;
2015-06-24 18:23:22 +02:00
errorID = MSG_ENTRIES_ADDED ;
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 ) {
2015-04-06 17:39:48 +02:00
printf ( " 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 ;
2015-04-06 17:39:48 +02:00
if ( fDebug ) LogPrintf ( " CDarkSendPool::AddScriptSig -- adding to finalTransaction %s \n " , newVin . scriptSig . ToString ( ) . substr ( 0 , 24 ) . c_str ( ) ) ;
}
}
for ( unsigned int i = 0 ; i < entries . size ( ) ; i + + ) {
if ( entries [ i ] . AddSig ( newVin ) ) {
if ( fDebug ) LogPrintf ( " CDarkSendPool::AddScriptSig -- adding %s \n " , newVin . scriptSig . ToString ( ) . substr ( 0 , 24 ) . c_str ( ) ) ;
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
LogPrintf ( " CDarksendPool::AddScriptSig -- Couldn't set sig! \n " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
2015-03-05 08:49:50 +01:00
// Check to make sure everything is signed
2015-03-02 00:09:33 +01:00
bool CDarksendPool : : SignaturesComplete ( ) {
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 ;
}
//
2015-03-05 09:10:15 +01:00
// Execute a Darksend denomination via a Masternode.
2014-12-09 02:17:57 +01:00
// 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 ) {
2015-06-24 18:25:43 +02:00
if ( txCollateral = = CMutableTransaction ( ) ) {
2014-12-09 02:17:57 +01:00
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());
2015-03-05 09:10:15 +01:00
// we should already be connected to a Masternode
2014-12-09 02:17:57 +01:00
if ( ! sessionFoundMasternode ) {
2015-03-05 09:10:15 +01:00
LogPrintf ( " CDarksendPool::SendDarksendDenominate() - No Masternode has been selected yet. \n " ) ;
2014-12-09 02:17:57 +01:00
UnlockCoins ( ) ;
SetNull ( true ) ;
return ;
}
2015-05-30 05:46:29 +02:00
if ( ! CheckDiskSpace ( ) ) {
UnlockCoins ( ) ;
2014-12-09 02:17:57 +01:00
return ;
2015-05-30 05:46:29 +02:00
}
2014-12-09 02:17:57 +01:00
if ( fMasterNode ) {
2015-03-05 09:10:15 +01:00
LogPrintf ( " CDarksendPool::SendDarksendDenominate() - Darksend from a Masternode is not supported currently. \n " ) ;
2015-05-30 05:46:29 +02:00
UnlockCoins ( ) ;
SetNull ( true ) ;
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 ;
2015-04-03 00:51:08 +02:00
CMutableTransaction tx ;
2014-12-09 02:17:57 +01:00
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-04 20:59:51 +01:00
LogPrintf ( " Submitting tx %s \n " , tx . ToString ( ) . c_str ( ) ) ;
2015-03-02 00:09:33 +01:00
2015-06-23 06:12:24 +02:00
if ( ! AcceptableInputs ( mempool , state , CTransaction ( tx ) , false , NULL , false , true ) ) {
2014-12-09 02:17:57 +01:00
LogPrintf ( " dsi -- transaction not valid! %s \n " , tx . ToString ( ) . c_str ( ) ) ;
2015-05-30 05:46:29 +02:00
UnlockCoins ( ) ;
SetNull ( true ) ;
2014-12-09 02:17:57 +01:00
return ;
}
}
// store our entry for later use
CDarkSendEntry e ;
e . Add ( vin , amount , txCollateral , vout ) ;
myEntries . push_back ( e ) ;
2015-04-06 08:52:37 +02:00
RelayIn ( myEntries [ 0 ] . sev , myEntries [ 0 ] . amount , txCollateral , myEntries [ 0 ] . vout ) ;
2014-12-09 02:17:57 +01:00
Check ( ) ;
}
2015-03-05 09:10:15 +01:00
// Incoming message from Masternode updating the progress of Darksend
2014-12-09 02:17:57 +01:00
// 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-04-15 00:40:28 +02:00
bool CDarksendPool : : StatusUpdate ( int newState , int newEntriesCount , int newAccepted , int & errorID , 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-04-15 00:40:28 +02:00
if ( errorID ! = MSG_NOERR ) strAutoDenomResult = _ ( " Masternode: " ) + " " + GetMessageByID ( errorID ) ;
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 ) ;
2015-04-15 00:40:28 +02:00
lastMessage = GetMessageByID ( errorID ) ;
2014-12-09 02:17:57 +01:00
}
2015-03-18 17:41:30 +01:00
if ( newAccepted = = 1 & & newSessionID ! = 0 ) {
2014-12-09 02:17:57 +01:00
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 ) ;
} else if ( newAccepted = = 0 & & sessionID = = 0 & & ! sessionFoundMasternode ) {
2015-03-05 09:10:15 +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 ) ;
2015-03-05 09:10:15 +01:00
DoAutomaticDenominating ( ) ; //try another Masternode
2014-12-09 02:17:57 +01:00
}
if ( sessionFoundMasternode ) return true ;
}
return true ;
}
2014-12-25 20:21:35 +01:00
//
2015-03-05 09:10:15 +01:00
// After we receive the finalized transaction from the Masternode, we must
2014-12-25 20:21:35 +01:00
// 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 ) {
2015-03-06 23:17:51 +01:00
if ( fMasterNode ) return false ;
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 ;
2015-04-03 00:51:08 +02:00
CAmount nValue1 = 0 ;
CAmount 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 ) ;
2015-05-30 05:46:29 +02:00
UnlockCoins ( ) ;
SetNull ( true ) ;
2015-04-06 08:52:37 +02:00
2014-12-09 02:17:57 +01:00
return false ;
}
2015-04-03 00:51:08 +02:00
const CKeyStore & keystore = * pwalletMain ;
2015-03-02 00:09:33 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::Sign - Signing my input %i \n " , mine ) ;
2015-04-03 00:51:08 +02:00
if ( ! SignSignature ( keystore , 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-04-06 08:52:37 +02:00
// push all of our signatures to the Masternode
if ( sigs . size ( ) > 0 & & node ! = NULL )
node - > PushMessage ( " dss " , sigs ) ;
2015-03-06 23:17:51 +01:00
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 ( ) ;
}
}
2015-03-05 08:49:50 +01:00
// Darksend transaction was completed (failed or successful)
2015-06-19 03:42:25 +02:00
void CDarksendPool : : CompletedTransaction ( bool error , int errorID )
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 ( ) ;
2015-05-30 05:46:29 +02:00
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 ;
}
2015-06-19 03:42:25 +02:00
lastMessage = GetMessageByID ( errorID ) ;
2014-12-09 02:17:57 +01:00
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-05 08:49:50 +01:00
LogPrintf ( " CDarksendPool::DoAutomaticDenominating - Last successful Darksend action was too recent \n " ) ;
strAutoDenomResult = _ ( " Last successful Darksend action was too recent. " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
if ( ! fEnableDarksend ) {
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 ;
}
2015-06-24 18:25:43 +02:00
if ( GetState ( ) ! = POOL_STATUS_ERROR & & GetState ( ) ! = POOL_STATUS_SUCCESS ) {
if ( GetMyTransactionCount ( ) > 0 ) {
2014-12-09 02:17:57 +01:00
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-05 09:10:15 +01:00
if ( fDebug ) LogPrintf ( " CDarksendPool::DoAutomaticDenominating - No Masternodes detected \n " ) ;
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-04-30 00:06:24 +02:00
CAmount nValueMin = CENT ;
CAmount nValueIn = 0 ;
CAmount nOnlyDenominatedBalance ;
CAmount nBalanceNeedsDenominated ;
2014-12-09 02:17:57 +01:00
2015-02-18 13:31:40 +01:00
// should not be less than fees in DARKSEND_COLLATERAL + few (lets say 5) smallest denoms
2015-04-30 00:06:24 +02:00
CAmount 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
2015-04-30 00:06:24 +02:00
CAmount 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
2015-04-30 00:06:24 +02:00
CAmount nAnonymizableBalance = pwalletMain - > GetAnonymizableBalance ( ) ;
if ( nBalanceNeedsAnonymized > nAnonymizableBalance ) nBalanceNeedsAnonymized = nAnonymizableBalance ;
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-04-30 00:06:24 +02:00
nOnlyDenominatedBalance = pwalletMain - > GetDenominatedBalance ( true , false , false ) ;
nBalanceNeedsDenominated = nBalanceNeedsAnonymized - nOnlyDenominatedBalance ;
if ( nBalanceNeedsDenominated > nValueIn ) nBalanceNeedsDenominated = nValueIn ;
if ( ! fDryRun ) return CreateDenominated ( nBalanceNeedsDenominated ) ;
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-06-24 18:30:05 +02:00
if ( fDryRun ) return true ;
2015-04-30 00:06:24 +02:00
nOnlyDenominatedBalance = pwalletMain - > GetDenominatedBalance ( true , false , false ) ;
nBalanceNeedsDenominated = nBalanceNeedsAnonymized - nOnlyDenominatedBalance ;
2015-06-24 18:30:05 +02:00
//check if we have should create more denominated inputs
if ( nBalanceNeedsDenominated > nOnlyDenominatedBalance ) return CreateDenominated ( nBalanceNeedsDenominated ) ;
2014-12-09 02:17:57 +01:00
2015-06-24 18:30:05 +02:00
//check if we have the collateral sized inputs
if ( ! pwalletMain - > HasCollateralInputs ( ) ) return MakeCollateralAmounts ( ) ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
std : : vector < CTxOut > vOut ;
2015-03-05 09:10:15 +01:00
// initial phase, find a Masternode
2014-12-09 02:17:57 +01:00
if ( ! sessionFoundMasternode ) {
2015-05-30 05:46:29 +02:00
// Clean if there is anything left from previous session
UnlockCoins ( ) ;
SetNull ( true ) ;
2014-12-09 02:17:57 +01:00
int nUseQueue = rand ( ) % 100 ;
2015-04-06 17:39:48 +02:00
UpdateState ( POOL_STATUS_ACCEPTING_ENTRIES ) ;
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 ;
}
2015-05-30 05:46:29 +02:00
//check our collateral nad create new if needed
std : : string strReason ;
CValidationState state ;
if ( txCollateral = = CMutableTransaction ( ) ) {
if ( ! pwalletMain - > CreateCollateralTransaction ( txCollateral , strReason ) ) {
LogPrintf ( " % -- create collateral error:%s \n " , __func__ , strReason . c_str ( ) ) ;
return false ;
}
} else {
2015-04-07 18:41:31 +02:00
if ( ! IsCollateralValid ( txCollateral ) ) {
2015-05-30 05:46:29 +02:00
LogPrintf ( " %s -- invalid collateral, recreating... \n " , __func__ ) ;
if ( ! pwalletMain - > CreateCollateralTransaction ( txCollateral , strReason ) ) {
LogPrintf ( " %s -- create collateral error: %s \n " , __func__ , strReason . c_str ( ) ) ;
return false ;
}
2015-04-07 18:41:31 +02:00
}
}
2014-12-09 02:17:57 +01:00
//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 ;
2015-03-05 09:10:15 +01:00
//don't reuse Masternodes
2014-12-09 02:17:57 +01:00
BOOST_FOREACH ( CTxIn usedVin , vecMasternodesUsed ) {
if ( dsq . vin = = usedVin ) {
continue ;
}
}
2015-04-07 03:45:30 +02:00
std : : vector < CTxIn > vTempCoins ;
std : : vector < COutput > vTempCoins2 ;
2014-12-30 01:09:34 +01:00
// Try to match their denominations if possible
2015-04-07 03:45:30 +02:00
if ( ! pwalletMain - > SelectCoinsByDenominations ( dsq . nDenom , nValueMin , nBalanceNeedsAnonymized , vTempCoins , vTempCoins2 , 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
}
2015-03-05 09:10:15 +01:00
// connect to Masternode and submit the queue request
2014-12-09 02:17:57 +01:00
if ( ConnectNode ( ( CAddress ) addr , NULL , true ) ) {
2015-05-30 04:46:09 +02:00
CNode * pnode = FindNode ( addr ) ;
if ( pnode )
2014-12-09 02:17:57 +01:00
{
2015-03-13 17:00:44 +01:00
CMasternode * pmn = mnodeman . Find ( dsq . vin ) ;
if ( pmn = = NULL )
{
LogPrintf ( " DoAutomaticDenominating --- dsq vin %s is not in masternode list! " , dsq . vin . ToString ( ) ) ;
continue ;
}
pSubmittedToMasternode = pmn ;
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-05-30 04:46:09 +02:00
pnode - > PushMessage ( " dsa " , sessionDenom , txCollateral ) ;
LogPrintf ( " DoAutomaticDenominating --- connected (from queue), sending dsa for %d - %s \n " , sessionDenom , pnode - > addr . ToString ( ) . c_str ( ) ) ;
2015-06-24 18:08:14 +02:00
strAutoDenomResult = _ ( " Mixing in progress... " ) ;
2015-04-06 17:39:48 +02:00
dsq . time = 0 ; //remove node
2014-12-09 02:17:57 +01:00
return true ;
}
} else {
LogPrintf ( " DoAutomaticDenominating --- error connecting \n " ) ;
2015-03-05 09:10:15 +01:00
strAutoDenomResult = _ ( " Error connecting to Masternode. " ) ;
2015-04-06 17:39:48 +02:00
dsq . time = 0 ; //remove node
2014-12-09 02:17:57 +01:00
return DoAutomaticDenominating ( ) ;
}
}
}
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 )
{
2015-03-05 09:10:15 +01:00
LogPrintf ( " DoAutomaticDenominating --- Masternode list is empty! \n " ) ;
2015-02-26 02:55:27 +01:00
return false ;
}
2015-03-05 09:10:15 +01:00
//don't reuse Masternodes
2014-12-09 02:17:57 +01:00
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-03-06 18:25:48 +01:00
pmn - > nLastDsq + mnodeman . CountMasternodesAboveProtocol ( MIN_POOL_PEER_PROTO_VERSION ) / 5 > mnodeman . nDsqCount ) {
2015-01-20 16:59:37 +01:00
i + + ;
continue ;
2014-12-09 02:17:57 +01:00
}
lastTimeChanged = GetTimeMillis ( ) ;
2015-03-05 09:10:15 +01:00
LogPrintf ( " DoAutomaticDenominating -- attempt %d connection to Masternode %s \n " , i , pmn - > addr . ToString ( ) . c_str ( ) ) ;
2015-02-26 02:55:27 +01:00
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
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-04-30 00:06:24 +02:00
std : : vector < CAmount > vecAmounts ;
2015-01-15 15:41:56 +01:00
pwalletMain - > ConvertList ( vCoins , vecAmounts ) ;
2015-05-30 04:46:09 +02:00
// try to get random denoms out of vecAmounts
while ( sessionDenom = = 0 )
sessionDenom = GetDenominationsByAmounts ( vecAmounts , true ) ;
2014-12-25 20:21:35 +01:00
2014-12-09 02:17:57 +01:00
pnode - > PushMessage ( " dsa " , sessionDenom , txCollateral ) ;
2015-05-30 04:46:09 +02:00
LogPrintf ( " DoAutomaticDenominating --- connected, sending dsa for %d \n " , sessionDenom ) ;
2015-06-24 18:08:14 +02:00
strAutoDenomResult = _ ( " Mixing in progress... " ) ;
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-03-05 09:10:15 +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
}
2015-06-24 18:08:14 +02:00
strAutoDenomResult = _ ( " Mixing in progress... " ) ;
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 ) ;
2015-03-05 08:49:50 +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 : : 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
2015-04-03 00:51:08 +02:00
scriptChange = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
2014-12-09 02:17:57 +01:00
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
{
CWalletTx wtx ;
int64_t nFeeRet = 0 ;
std : : string strFail = " " ;
vector < pair < CScript , int64_t > > vecSend ;
2015-06-22 19:59:27 +02:00
CCoinControl * coinControl = NULL ;
2014-12-09 02:17:57 +01:00
2015-06-22 19:59:27 +02:00
// make our collateral address
CReserveKey reservekeyCollateral ( pwalletMain ) ;
// make our change address
CReserveKey reservekeyChange ( pwalletMain ) ;
CScript scriptCollateral ;
CPubKey vchPubKey ;
assert ( reservekeyCollateral . GetReservedKey ( vchPubKey ) ) ; // should never fail, as we just unlocked
scriptCollateral = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
vecSend . push_back ( make_pair ( scriptCollateral , DARKSEND_COLLATERAL * 4 ) ) ;
2014-12-09 02:17:57 +01:00
2015-01-27 05:39:27 +01:00
// try to use non-denominated and not mn-like funds
2015-06-22 19:59:27 +02:00
bool success = pwalletMain - > CreateTransaction ( vecSend , wtx , reservekeyChange ,
2015-01-27 05:39:27 +01:00
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
2015-06-22 19:59:27 +02:00
success = pwalletMain - > CreateTransaction ( vecSend , wtx , reservekeyChange ,
2015-01-27 05:39:27 +01:00
nFeeRet , strFail , coinControl , ONLY_DENOMINATED ) ;
if ( ! success ) {
2015-06-22 19:59:27 +02:00
LogPrintf ( " MakeCollateralAmounts: ONLY_DENOMINATED Error - %s \n " , strFail ) ;
reservekeyCollateral . ReturnKey ( ) ;
2015-01-27 05:39:27 +01:00
return false ;
}
2014-12-09 02:17:57 +01:00
}
2015-06-22 19:59:27 +02:00
reservekeyCollateral . KeepKey ( ) ;
2015-06-24 18:30:05 +02:00
LogPrintf ( " MakeCollateralAmounts: tx %s \n " , wtx . GetHash ( ) . GetHex ( ) ) ;
2015-01-25 22:18:26 +01:00
// use the same cachedLastSuccess as for DS mixinx to prevent race
2015-06-24 18:30:05 +02:00
if ( ! pwalletMain - > CommitTransaction ( wtx , reservekeyChange ) ) {
2015-06-23 22:44:20 +02:00
LogPrintf ( " MakeCollateralAmounts: CommitTransaction failed! \n " ) ;
2015-06-24 18:30:05 +02:00
return false ;
}
2014-12-09 02:17:57 +01:00
2015-06-24 18:30:05 +02:00
cachedLastSuccess = chainActive . Tip ( ) - > nHeight ;
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
{
CWalletTx wtx ;
int64_t nFeeRet = 0 ;
std : : string strFail = " " ;
vector < pair < CScript , int64_t > > vecSend ;
int64_t nValueLeft = nTotalValue ;
2015-06-22 19:59:27 +02:00
// make our collateral address
CReserveKey reservekeyCollateral ( pwalletMain ) ;
// make our change address
CReserveKey reservekeyChange ( pwalletMain ) ;
// make our denom addresses
CReserveKey reservekeyDenom ( pwalletMain ) ;
CScript scriptCollateral ;
CPubKey vchPubKey ;
assert ( reservekeyCollateral . GetReservedKey ( vchPubKey ) ) ; // should never fail, as we just unlocked
scriptCollateral = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
2015-01-27 05:13:34 +01:00
// ****** Add collateral outputs ************ /
if ( ! pwalletMain - > HasCollateralInputs ( ) ) {
2015-06-22 19:59:27 +02:00
vecSend . push_back ( make_pair ( scriptCollateral , DARKSEND_COLLATERAL * 4 ) ) ;
2015-02-18 13:31:40 +01:00
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-06-22 19:59:27 +02:00
CScript scriptDenom ;
2015-01-15 15:41:56 +01:00
CPubKey vchPubKey ;
//use a unique change address
2015-06-22 19:59:27 +02:00
assert ( reservekeyDenom . GetReservedKey ( vchPubKey ) ) ; // should never fail, as we just unlocked
scriptDenom = GetScriptForDestination ( vchPubKey . GetID ( ) ) ;
// TODO: do not keep reservekeyDenom here
reservekeyDenom . KeepKey ( ) ;
2015-01-15 15:41:56 +01:00
2015-06-22 19:59:27 +02:00
vecSend . push_back ( make_pair ( scriptDenom , v ) ) ;
2015-01-15 15:41:56 +01:00
//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 ;
2015-06-22 19:59:27 +02:00
bool success = pwalletMain - > CreateTransaction ( vecSend , wtx , reservekeyChange ,
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 ( ) ) ;
2015-06-22 19:59:27 +02:00
// TODO: return reservekeyDenom here
reservekeyCollateral . ReturnKey ( ) ;
2015-01-15 15:41:56 +01:00
return false ;
}
2015-06-22 19:59:27 +02:00
// TODO: keep reservekeyDenom here
reservekeyCollateral . KeepKey ( ) ;
2015-01-25 22:18:26 +01:00
// use the same cachedLastSuccess as for DS mixinx to prevent race
2015-06-22 19:59:27 +02:00
if ( pwalletMain - > CommitTransaction ( wtx , reservekeyChange ) )
2015-01-25 22:18:26 +01:00
cachedLastSuccess = chainActive . Tip ( ) - > nHeight ;
2015-06-22 19:59:27 +02:00
else
LogPrintf ( " CreateDenominated: CommitTransaction failed! \n " ) ;
2015-01-15 15:41:56 +01:00
2015-06-22 19:59:27 +02:00
LogPrintf ( " CreateDenominated: tx %s \n " , wtx . GetHash ( ) . GetHex ( ) . c_str ( ) ) ;
2015-01-15 15:41:56 +01:00
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
{
2015-04-06 17:39:48 +02:00
if ( GetDenominations ( vout ) = = 0 ) return false ;
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-04-15 00:40:28 +02:00
bool CDarksendPool : : IsCompatibleWithSession ( int64_t nDenom , CTransaction txCollateral , int & errorID )
2014-12-09 02:17:57 +01:00
{
2015-04-07 01:07:25 +02:00
if ( nDenom = = 0 ) return false ;
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-04-15 00:40:28 +02:00
errorID = ERR_INVALID_COLLATERAL ;
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 ) {
2015-03-18 17:41:30 +01:00
sessionID = 1 + ( rand ( ) % 999999 ) ;
2014-12-09 02:17:57 +01:00
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 ) ;
vecSessionCollateral . push_back ( txCollateral ) ;
return true ;
}
2015-04-06 17:39:48 +02:00
if ( ( state ! = POOL_STATUS_ACCEPTING_ENTRIES & & state ! = POOL_STATUS_QUEUE ) | | sessionUsers > = GetMaxPoolTransactions ( ) ) {
2015-04-15 00:40:28 +02:00
if ( ( state ! = POOL_STATUS_ACCEPTING_ENTRIES & & state ! = POOL_STATUS_QUEUE ) ) errorID = ERR_MODE ;
if ( sessionUsers > = GetMaxPoolTransactions ( ) ) errorID = ERR_QUEUE_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-04-15 00:40:28 +02:00
errorID = ERR_DENOM ;
2014-12-09 02:17:57 +01:00
return false ;
}
2015-04-06 17:39:48 +02:00
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 " ;
}
}
2015-03-06 23:17:51 +01:00
int CDarksendPool : : GetDenominations ( const std : : vector < CTxDSOut > & vout ) {
std : : vector < CTxOut > vout2 ;
BOOST_FOREACH ( CTxDSOut out , vout )
vout2 . push_back ( out ) ;
return GetDenominations ( vout2 ) ;
}
2014-12-09 02:17:57 +01:00
// return a bitshifted integer representing the denominations in this list
2015-05-30 04:46:09 +02:00
int CDarksendPool : : GetDenominations ( const std : : vector < CTxOut > & vout , bool fRandDenom ) {
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 )
2015-05-30 04:46:09 +02:00
denom | = ( ( fRandDenom ? rand ( ) % 2 : 1 ) * s . second ) < < c + + ;
2014-12-09 02:17:57 +01:00
// 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-05-30 04:46:09 +02:00
int CDarksendPool : : GetDenominationsByAmounts ( std : : vector < int64_t > & vecAmount , bool fRandDenom ) {
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 + + ;
}
2015-05-30 04:46:09 +02:00
return GetDenominations ( vout1 , fRandDenom ) ;
2014-12-09 02:17:57 +01:00
}
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
}
return GetDenominations ( vout1 ) ;
}
2015-04-15 00:40:28 +02:00
std : : string CDarksendPool : : GetMessageByID ( int messageID ) {
switch ( messageID ) {
case ERR_ALREADY_HAVE : return _ ( " Already have that input. " ) ;
case ERR_DENOM : return _ ( " No matching denominations found for mixing. " ) ;
case ERR_ENTRIES_FULL : return _ ( " Entries are full. " ) ;
case ERR_EXISTING_TX : return _ ( " Not compatible with existing transactions. " ) ;
case ERR_FEES : return _ ( " Transaction fees are too high. " ) ;
case ERR_INVALID_COLLATERAL : return _ ( " Collateral not valid. " ) ;
case ERR_INVALID_INPUT : return _ ( " Input is not valid. " ) ;
case ERR_INVALID_SCRIPT : return _ ( " Invalid script detected. " ) ;
case ERR_INVALID_TX : return _ ( " Transaction not valid. " ) ;
case ERR_MAXIMUM : return _ ( " Value more than Darksend pool maximum allows. " ) ;
case ERR_MN_LIST : return _ ( " Not in the Masternode list. " ) ;
case ERR_MODE : return _ ( " Incompatible mode. " ) ;
case ERR_NON_STANDARD_PUBKEY : return _ ( " Non-standard public key detected. " ) ;
case ERR_NOT_A_MN : return _ ( " This is not a Masternode. " ) ;
case ERR_QUEUE_FULL : return _ ( " Masternode queue is full. " ) ;
case ERR_RECENT : return _ ( " Last Darksend was too recent. " ) ;
case ERR_SESSION : return _ ( " Session not complete! " ) ;
case ERR_MISSING_TX : return _ ( " Missing input transaction information. " ) ;
case ERR_VERSION : return _ ( " Incompatible version. " ) ;
case MSG_SUCCESS : return _ ( " Transaction created successfully. " ) ;
2015-06-24 18:23:22 +02:00
case MSG_ENTRIES_ADDED : return _ ( " Your entries added successfully. " ) ;
2015-04-15 00:40:28 +02:00
case MSG_NOERR :
default :
return " " ;
}
}
2014-12-09 02:17:57 +01:00
bool CDarkSendSigner : : IsVinAssociatedWithPubkey ( CTxIn & vin , CPubKey & pubkey ) {
CScript payee2 ;
2015-04-03 00:51:08 +02:00
payee2 = GetScriptForDestination ( pubkey . GetID ( ) ) ;
2014-12-09 02:17:57 +01:00
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-03-05 09:10:15 +01:00
LogPrintf ( " CDarksendQueue():Relay - ERROR: Invalid Masternodeprivkey: '%s' \n " , errorMessage . c_str ( ) ) ;
2015-01-18 16:28:16 +01:00
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 ;
}
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-03-05 09:10:15 +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
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 ) ;
}
}
2015-03-06 23:17:51 +01:00
void CDarksendPool : : RelayIn ( const std : : vector < CTxDSIn > & vin , const int64_t & nAmount , const CTransaction & txCollateral , const std : : vector < CTxDSOut > & vout )
2015-03-02 00:09:33 +01:00
{
2015-03-06 23:17:51 +01:00
std : : vector < CTxIn > vin2 ;
std : : vector < CTxOut > vout2 ;
BOOST_FOREACH ( CTxDSIn in , vin )
vin2 . push_back ( in ) ;
BOOST_FOREACH ( CTxDSOut out , vout )
vout2 . push_back ( out ) ;
2015-03-22 04:10:34 +01:00
LOCK ( cs_vNodes ) ;
2015-03-02 00:09:33 +01:00
BOOST_FOREACH ( CNode * pnode , vNodes )
{
if ( ! pSubmittedToMasternode ) return ;
2015-06-24 18:25:43 +02:00
if ( ( CNetAddr ) pSubmittedToMasternode - > addr ! = ( CNetAddr ) pnode - > addr ) continue ;
2015-03-02 00:09:33 +01:00
LogPrintf ( " RelayIn - found master, relaying message - %s \n " , pnode - > addr . ToString ( ) . c_str ( ) ) ;
2015-03-06 23:17:51 +01:00
pnode - > PushMessage ( " dsi " , vin2 , nAmount , txCollateral , vout2 ) ;
2015-03-02 00:09:33 +01:00
}
}
2015-04-15 00:40:28 +02:00
void CDarksendPool : : RelayStatus ( const int sessionID , const int newState , const int newEntriesCount , const int newAccepted , const int errorID )
2015-03-02 00:09:33 +01:00
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
2015-04-15 00:40:28 +02:00
pnode - > PushMessage ( " dssu " , sessionID , newState , newEntriesCount , newAccepted , errorID ) ;
2015-03-02 00:09:33 +01:00
}
2015-04-15 00:40:28 +02:00
void CDarksendPool : : RelayCompletedTransaction ( const int sessionID , const bool error , const int errorID )
2015-03-02 00:09:33 +01:00
{
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
2015-04-15 00:40:28 +02:00
pnode - > PushMessage ( " dsc " , sessionID , error , errorID ) ;
2015-03-02 00:09:33 +01:00
}
2015-02-09 20:28:29 +01:00
//TODO: Rename/move to core
2014-12-09 02:17:57 +01:00
void ThreadCheckDarkSendPool ( )
{
2015-03-05 09:10:15 +01:00
if ( fLiteMode ) return ; //disable all Darksend/Masternode related functionality
2015-01-18 16:28:16 +01:00
2014-12-09 02:17:57 +01:00
// Make this thread recognisable as the wallet flushing thread
2015-03-19 15:15:08 +01:00
RenameThread ( " dash-darksend " ) ;
2014-12-09 02:17:57 +01:00
unsigned int c = 0 ;
2014-12-06 20:41:53 +01:00
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
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-03-05 09:10:15 +01:00
//try to sync the Masternode list and payment list every 5 seconds from at least 3 nodes
2015-07-04 16:49:49 +02:00
if ( c % 5 = = 0 & & RequestedMasternodeAssets < = 5 ) {
2014-12-09 02:17:57 +01:00
bool fIsInitialDownload = IsInitialBlockDownload ( ) ;
if ( ! fIsInitialDownload ) {
2015-07-02 01:46:03 +02:00
CBlockIndex * pindexPrev = chainActive . Tip ( ) ;
if ( pindexPrev ! = NULL ) {
2015-07-06 20:12:56 +02:00
if ( pindexPrev - > nTime > GetAdjustedTime ( ) - 60 )
2015-07-02 01:46:03 +02:00
{
2014-12-09 02:17:57 +01:00
2015-07-02 01:46:03 +02:00
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
{
if ( pnode - > nVersion > = MIN_POOL_PEER_PROTO_VERSION ) {
//keep track of who we've asked for the list
if ( pnode - > HasFulfilledRequest ( " mnsync " ) ) continue ;
pnode - > FulfilledRequest ( " mnsync " ) ;
2014-12-09 02:17:57 +01:00
2015-07-02 01:46:03 +02:00
//request full mn list only if Masternodes.dat was updated quite a long time ago
2015-07-04 16:49:49 +02:00
if ( RequestedMasternodeAssets = = 0 | | RequestedMasternodeAssets = = 1 ) {
2015-07-10 00:08:26 +02:00
LogPrintf ( " Successfully synced, asking for Masternode list \n " ) ;
2015-07-04 16:49:49 +02:00
mnodeman . DsegUpdate ( pnode ) ;
pnode - > PushMessage ( " getsporks " ) ; //get current network sporks
}
2015-07-10 00:08:26 +02:00
if ( RequestedMasternodeAssets = = 2 | | RequestedMasternodeAssets = = 3 ) {
LogPrintf ( " Successfully synced, asking for Masternode payee list \n " ) ;
2015-07-04 16:49:49 +02:00
pnode - > PushMessage ( " mnget " ) ; //sync payees
2015-07-10 00:08:26 +02:00
}
2015-07-04 16:49:49 +02:00
if ( RequestedMasternodeAssets = = 4 | | RequestedMasternodeAssets = = 5 ) {
2015-07-10 00:08:26 +02:00
LogPrintf ( " Successfully synced, asking for Masternode Budget votes / Finalized budgets \n " ) ;
2015-07-04 16:49:49 +02:00
uint256 n = 0 ;
pnode - > PushMessage ( " mnvs " , n ) ; //sync masternode votes
}
2015-02-23 21:01:21 +01:00
2015-07-02 01:46:03 +02:00
RequestedMasternodeAssets + + ;
break ;
}
}
2014-12-09 02:17:57 +01:00
}
}
}
2015-05-04 17:04:09 +02:00
} else if ( c % 60 = = 0 & & RequestedMasternodeAssets = = 3 ) {
RequestedMasternodeAssets = MASTERNODE_LIST_SYNCED ; //done syncing
2014-12-09 02:17:57 +01:00
}
if ( c % 60 = = 0 ) {
2015-03-05 09:10:15 +01:00
//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 ( ) ;
}
2015-04-06 17:39:48 +02:00
if ( darkSendPool . GetState ( ) = = POOL_STATUS_IDLE & & c % 6 = = 0 ) {
darkSendPool . DoAutomaticDenominating ( ) ;
2014-12-09 02:17:57 +01:00
}
}
}