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"
2016-01-24 20:05:31 +01:00
# include "masternode-payments.h"
# include "masternode-sync.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-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-19 15:15:08 +01:00
/* *** BEGIN DARKSEND MAGIC - DASH **********
2015-03-18 00:06:58 +01:00
Copyright ( c ) 2014 - 2015 , Dash Developers
2016-01-31 14:11:16 +01:00
eduffield - evan @ dash . org
udjinm6 - udjinm6 @ dash . org
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-08-07 06:48:55 +02:00
if ( ! masternodeSync . IsBlockchainSynced ( ) ) 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-07-19 01:20:48 +02:00
pmn - > nLastDsq + mnodeman . CountEnabled ( MIN_POOL_PEER_PROTO_VERSION ) / 5 > mnodeman . nDsqCount ) {
2015-07-31 17:46:47 +02:00
LogPrintf ( " dsa -- last dsq too recent, must wait. %s \n " , pfrom - > addr . ToString ( ) ) ;
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-07-31 17:46:47 +02:00
LogPrintf ( " dsq - message doesn't match current Masternode - %s != %s \n " , pSubmittedToMasternode - > addr . ToString ( ) , addr . ToString ( ) ) ;
2014-12-09 02:17:57 +01:00
return ;
}
2015-03-02 00:09:33 +01:00
if ( state = = POOL_STATUS_QUEUE ) {
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " Darksend queue is ready - %s \n " , addr . ToString ( ) ) ;
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-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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-07-19 01:20:48 +02:00
pmn - > nLastDsq + mnodeman . CountEnabled ( MIN_POOL_PEER_PROTO_VERSION ) / 5 > mnodeman . nDsqCount ) {
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " dsq -- Masternode sending too many dsq messages. %s \n " , pmn - > addr . ToString ( ) ) ;
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-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " dsq - new Darksend queue object - %s \n " , addr . ToString ( ) ) ;
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 ;
2016-01-24 05:21:14 +01:00
CAmount nAmount ;
2014-12-09 02:17:57 +01:00
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
{
2016-01-24 05:21:14 +01:00
CAmount nValueIn = 0 ;
CAmount nValueOut = 0 ;
2014-12-09 02:17:57 +01:00
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 ) {
2015-07-31 17:46:47 +02:00
LogPrintf ( " dsi - non-standard pubkey detected! %s \n " , o . scriptPubKey . ToString ( ) ) ;
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 ( ) ) {
2015-07-31 17:46:47 +02:00
LogPrintf ( " dsi - invalid script! %s \n " , o . scriptPubKey . ToString ( ) ) ;
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 ) ;
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " dsi -- tx in %s \n " , i . ToString ( ) ) ;
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-07-31 17:46:47 +02:00
LogPrintf ( " dsi -- more than Darksend pool max! %s \n " , tx . ToString ( ) ) ;
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 ) {
2015-07-31 17:46:47 +02:00
LogPrintf ( " dsi -- fees are too high! %s \n " , tx . ToString ( ) ) ;
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 {
2015-07-31 17:46:47 +02:00
LogPrintf ( " dsi -- missing input tx! %s \n " , tx . ToString ( ) ) ;
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-07-30 15:44:18 +02:00
{
LOCK ( cs_main ) ;
if ( ! AcceptableInputs ( mempool , state , CTransaction ( tx ) , false , NULL , false , true ) ) {
LogPrintf ( " dsi -- transaction not valid! \n " ) ;
errorID = ERR_INVALID_TX ;
pfrom - > PushMessage ( " dssu " , sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_REJECTED , errorID ) ;
return ;
}
2014-12-09 02:17:57 +01:00
}
}
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-07-31 17:46:47 +02:00
//LogPrintf("dssu - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), pfrom->addr.ToString());
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-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " dssu - state: %i entriesCount: %i accepted: %i error: %s \n " , state , entriesCount , accepted , GetMessageByID ( errorID ) ) ;
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 ;
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " -- sigs count %d %d \n " , ( int ) sigs . size ( ) , count ) ;
2014-12-09 02:17:57 +01:00
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-07-31 17:46:47 +02:00
//LogPrintf("dsc - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), pfrom->addr.ToString());
2015-03-02 00:09:33 +01:00
return ;
}
int sessionIDMessage ;
CTransaction txNew ;
vRecv > > sessionIDMessage > > txNew ;
if ( sessionID ! = sessionIDMessage ) {
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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-07-31 17:46:47 +02:00
//LogPrintf("dsc - message doesn't match current Masternode - %s != %s\n", pSubmittedToMasternode->addr.ToString(), pfrom->addr.ToString());
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-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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
}
}
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-07-26 00:43:40 +02:00
void CDarksendPool : : SetNull ( ) {
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
// MN side
sessionUsers = 0 ;
vecSessionCollateral . clear ( ) ;
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
// Client side
2014-12-09 02:17:57 +01:00
entriesCount = 0 ;
lastEntryAccepted = 0 ;
countEntriesAccepted = 0 ;
sessionFoundMasternode = false ;
2015-07-26 00:43:40 +02:00
// Both sides
state = POOL_STATUS_IDLE ;
sessionID = 0 ;
sessionDenom = 0 ;
entries . clear ( ) ;
finalTransaction . vin . clear ( ) ;
finalTransaction . vout . clear ( ) ;
lastTimeChanged = GetTimeMillis ( ) ;
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 ( ) {
2015-08-07 06:08:37 +02:00
while ( true ) {
TRY_LOCK ( pwalletMain - > cs_wallet , lockWallet ) ;
2015-08-08 23:48:09 +02:00
if ( ! lockWallet ) { MilliSleep ( 50 ) ; continue ; }
2015-08-07 06:08:37 +02:00
BOOST_FOREACH ( CTxIn v , lockedCoins )
pwalletMain - > UnlockCoin ( v . prevout ) ;
break ;
}
2014-12-09 02:17:57 +01:00
lockedCoins . clear ( ) ;
}
2015-06-24 18:08:14 +02:00
std : : string CDarksendPool : : GetStatus ( )
{
static int showingDarkSendMessage = 0 ;
2015-07-26 01:24:19 +02:00
showingDarkSendMessage + = 10 ;
2015-06-24 18:08:14 +02:00
std : : string suffix = " " ;
2015-08-03 21:53:00 +02:00
if ( chainActive . Tip ( ) - > nHeight - cachedLastSuccess < minBlockSpacing | | ! masternodeSync . IsBlockchainSynced ( ) ) {
2015-06-24 18:08:14 +02:00
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-08-03 18:24:23 +02:00
if ( fMasterNode ) LogPrint ( " darksend " , " CDarksendPool::Check() - entries count %lu \n " , entries . size ( ) ) ;
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
2015-07-26 00:43:40 +02:00
if ( fMasterNode ) {
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::Check() - entries count %lu \n " , entries . size ( ) ) ;
2015-07-26 00:43:40 +02:00
// If entries is full, then move on to the next phase
if ( state = = POOL_STATUS_ACCEPTING_ENTRIES & & ( int ) entries . size ( ) > = GetMaxPoolTransactions ( ) )
{
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::Check() -- TRYING TRANSACTION \n " ) ;
2015-07-26 00:43:40 +02:00
UpdateState ( POOL_STATUS_FINALIZE_TRANSACTION ) ;
}
2014-12-09 02:17:57 +01:00
}
// create the finalized transaction for distribution to the clients
2015-03-02 00:09:33 +01:00
if ( state = = POOL_STATUS_FINALIZE_TRANSACTION ) {
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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-08-21 03:28:17 +02:00
// BIP69 https://github.com/kristovatlas/bips/blob/master/bip-0069.mediawiki
sort ( txNew . vin . begin ( ) , txNew . vin . end ( ) ) ;
sort ( txNew . vout . begin ( ) , txNew . vout . end ( ) ) ;
2015-03-02 00:09:33 +01:00
2014-12-09 02:17:57 +01:00
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " Transaction 1: %s \n " , txNew . ToString ( ) ) ;
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
2015-07-26 00:43:40 +02:00
if ( fMasterNode & & state = = POOL_STATUS_SIGNING & & SignaturesComplete ( ) ) {
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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 ) {
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::Check() -- timeout, RESETTING \n " ) ;
2015-03-02 00:09:33 +01:00
UnlockCoins ( ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
if ( fMasterNode ) RelayStatus ( sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_RESET ) ;
2015-03-02 00:09:33 +01:00
}
}
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
void CDarksendPool : : CheckFinalTransaction ( )
{
2015-07-26 00:43:40 +02:00
if ( ! fMasterNode ) return ; // check and relay final tx only on masternode
2015-03-02 00:09:33 +01:00
CWalletTx txNew = CWalletTx ( pwalletMain , finalTransaction ) ;
LOCK2 ( cs_main , pwalletMain - > cs_wallet ) ;
{
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " Transaction 2: %s \n " , txNew . ToString ( ) ) ;
2015-03-02 00:09:33 +01:00
2015-07-26 00:43:40 +02:00
// See if the transaction is valid
if ( ! txNew . AcceptToMemoryPool ( false , true , true ) )
{
LogPrintf ( " CDarksendPool::Check() - CommitTransaction : Error: Transaction not valid \n " ) ;
SetNull ( ) ;
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
// not much we can do in this case
UpdateState ( POOL_STATUS_ACCEPTING_ENTRIES ) ;
RelayCompletedTransaction ( sessionID , true , ERR_INVALID_TX ) ;
return ;
}
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
LogPrintf ( " CDarksendPool::Check() -- IS MASTER -- TRANSMITTING DARKSEND \n " ) ;
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
// sign a message
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02: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-07-26 00:43:40 +02:00
if ( ! darkSendSigner . SetKey ( strMasterNodePrivKey , strError , key2 , pubkey2 ) )
{
2015-07-31 17:46:47 +02:00
LogPrintf ( " CDarksendPool::Check() - ERROR: Invalid Masternodeprivkey: '%s' \n " , strError ) ;
2015-07-26 00:43:40 +02:00
return ;
}
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02: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-07-26 00:43:40 +02: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-07-26 00:43:40 +02: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-07-26 00:43:40 +02:00
mapDarksendBroadcastTxes . insert ( make_pair ( txNew . GetHash ( ) , dstx ) ) ;
}
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
CInv inv ( MSG_DSTX , txNew . GetHash ( ) ) ;
2015-08-05 21:39:43 +02:00
RelayInv ( inv ) ;
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
// Tell the clients it was successful
RelayCompletedTransaction ( sessionID , false , MSG_SUCCESS ) ;
2015-03-02 00:09:33 +01:00
2015-07-26 00:43:40 +02:00
// Randomly charge clients
ChargeRandomFees ( ) ;
2015-03-02 00:09:33 +01:00
2015-07-26 00:43:40 +02:00
// Reset
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::Check() -- COMPLETED -- RESETTING \n " ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
RelayStatus ( sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_RESET ) ;
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 ( ) {
2015-07-26 00:43:40 +02:00
if ( ! fMasterNode ) return ;
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
//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 ;
2014-12-09 02:17:57 +01:00
}
}
2015-07-26 00:43:40 +02:00
// This queue entry didn't send us the promised transaction
if ( ! found ) {
LogPrintf ( " CDarksendPool::ChargeFees -- found uncooperative node (didn't send transaction). Found offence. \n " ) ;
offences + + ;
}
2014-12-09 02:17:57 +01:00
}
2015-07-26 00:43:40 +02:00
}
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
if ( state = = POOL_STATUS_SIGNING ) {
// who didn't sign?
BOOST_FOREACH ( const CDarkSendEntry v , entries ) {
BOOST_FOREACH ( const CTxDSIn s , v . sev ) {
if ( ! s . fHasSig ) {
LogPrintf ( " CDarksendPool::ChargeFees -- found uncooperative node (didn't sign). Found offence \n " ) ;
offences + + ;
2014-12-09 02:17:57 +01:00
}
}
}
2015-07-26 00:43:40 +02:00
}
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
r = rand ( ) % 100 ;
int target = 0 ;
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
//mostly offending?
if ( offences > = Params ( ) . PoolMaxTransactions ( ) - 1 & & r > 33 ) return ;
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
//everyone is an offender? That's not right
if ( offences > = Params ( ) . PoolMaxTransactions ( ) ) return ;
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
//charge one of the offenders randomly
if ( offences > 1 ) target = 50 ;
2014-12-25 20:21:35 +01:00
2015-07-26 00:43:40 +02:00
//pick random client to charge
r = rand ( ) % 100 ;
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
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 ) {
LogPrintf ( " CDarksendPool::ChargeFees -- found uncooperative node (didn't send transaction). charging fees. \n " ) ;
CWalletTx wtxCollateral = CWalletTx ( pwalletMain , txCollateral ) ;
// Broadcast
if ( ! wtxCollateral . AcceptToMemoryPool ( true ) )
{
// This must not fail. The transaction has already been signed and recorded.
LogPrintf ( " CDarksendPool::ChargeFees() : Error: Transaction not valid " ) ;
2014-12-09 02:17:57 +01:00
}
2015-07-26 00:43:40 +02:00
wtxCollateral . RelayWalletTransaction ( ) ;
return ;
}
}
}
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
if ( state = = POOL_STATUS_SIGNING ) {
// who didn't sign?
BOOST_FOREACH ( const CDarkSendEntry v , entries ) {
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
2015-07-26 00:43:40 +02:00
CWalletTx wtxCollateral = CWalletTx ( pwalletMain , v . collateral ) ;
2014-12-09 02:17:57 +01:00
// Broadcast
2015-07-26 00:43:40 +02: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 :
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " CDarksendPool::CheckTimeout() -- Session complete -- Running Check() \n " ) ;
2015-06-24 18:08:14 +02:00
Check ( ) ;
break ;
case POOL_STATUS_ERROR :
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " CDarksendPool::CheckTimeout() -- Pool error -- Running Check() \n " ) ;
2015-06-24 18:08:14 +02:00
Check ( ) ;
break ;
case POOL_STATUS_SUCCESS :
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " CDarksendPool::CheckTimeout() -- Pool success -- Running Check() \n " ) ;
2015-06-24 18:08:14 +02:00
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 ;
2015-07-26 00:43:40 +02:00
vector < CDarksendQueue > : : iterator it = vecDarksendQueue . begin ( ) ;
while ( it ! = vecDarksendQueue . end ( ) ) {
2014-12-09 02:17:57 +01:00
if ( ( * it ) . IsExpired ( ) ) {
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " CDarksendPool::CheckTimeout() : Removing expired queue entry - %d \n " , c ) ;
2015-07-26 00:43:40 +02:00
it = vecDarksendQueue . erase ( it ) ;
} else + + it ;
2014-12-09 02:17:57 +01:00
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 ;
// check for a timeout and reset if needed
2015-07-26 00:43:40 +02:00
vector < CDarkSendEntry > : : iterator it2 = entries . begin ( ) ;
while ( it2 ! = entries . end ( ) ) {
2014-12-09 02:17:57 +01:00
if ( ( * it2 ) . IsExpired ( ) ) {
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " CDarksendPool::CheckTimeout() : Removing expired entry - %d \n " , c ) ;
2015-07-26 00:43:40 +02:00
it2 = entries . erase ( it2 ) ;
if ( entries . size ( ) = = 0 ) {
2014-12-09 02:17:57 +01:00
UnlockCoins ( ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
2014-12-09 02:17:57 +01:00
}
if ( fMasterNode ) {
2015-06-24 18:25:43 +02:00
RelayStatus ( sessionID , GetState ( ) , GetEntriesCount ( ) , MASTERNODE_RESET ) ;
2014-12-09 02:17:57 +01:00
}
2015-07-26 00:43:40 +02:00
} else + + it2 ;
2014-12-09 02:17:57 +01:00
c + + ;
}
if ( GetTimeMillis ( ) - lastTimeChanged > = ( DARKSEND_QUEUE_TIMEOUT * 1000 ) + addLagTime ) {
2015-05-30 05:46:29 +02:00
UnlockCoins ( ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
2014-12-09 02:17:57 +01:00
}
} else if ( GetTimeMillis ( ) - lastTimeChanged > = ( DARKSEND_QUEUE_TIMEOUT * 1000 ) + addLagTime ) {
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::CheckTimeout() -- Session timed out (%ds) -- resetting \n " , DARKSEND_QUEUE_TIMEOUT ) ;
2014-12-09 02:17:57 +01:00
UnlockCoins ( ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
2014-12-09 02:17:57 +01:00
UpdateState ( POOL_STATUS_ERROR ) ;
2015-07-26 00:43:40 +02:00
lastMessage = _ ( " Session timed out. " ) ;
2014-12-09 02:17:57 +01:00
}
if ( state = = POOL_STATUS_SIGNING & & GetTimeMillis ( ) - lastTimeChanged > = ( DARKSEND_SIGNING_TIMEOUT * 1000 ) + addLagTime ) {
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::CheckTimeout() -- Session timed out (%ds) -- restting \n " , DARKSEND_SIGNING_TIMEOUT ) ;
2015-03-02 00:09:33 +01:00
ChargeFees ( ) ;
UnlockCoins ( ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
2014-12-09 02:17:57 +01:00
2015-03-02 00:09:33 +01:00
UpdateState ( POOL_STATUS_ERROR ) ;
2015-07-26 00:43:40 +02:00
lastMessage = _ ( " Signing timed out. " ) ;
2015-03-02 00:09:33 +01:00
}
}
//
// 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-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::SignatureValid() - Sign with sig %s \n " , newSig . ToString ( ) . substr ( 0 , 24 ) ) ;
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-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " CDarksendPool::SignatureValid() - Signing - Error signing input %u \n " , n ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
}
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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 ;
2016-01-24 05:21:14 +01:00
CAmount nValueIn = 0 ;
CAmount nValueOut = 0 ;
2014-12-09 02:17:57 +01:00
bool missingTx = false ;
BOOST_FOREACH ( const CTxOut o , txCollateral . vout ) {
nValueOut + = o . nValue ;
if ( ! o . scriptPubKey . IsNormalPaymentScript ( ) ) {
2015-09-09 20:34:52 +02:00
LogPrintf ( " CDarksendPool::IsCollateralValid - Invalid Script %s " , txCollateral . ToString ( ) ) ;
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-09-09 20:34:52 +02:00
LogPrint ( " darksend " , " CDarksendPool::IsCollateralValid - Unknown inputs in collateral transaction - %s " , txCollateral . ToString ( ) ) ;
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-09-09 20:34:52 +02:00
LogPrint ( " darksend " , " CDarksendPool::IsCollateralValid - did not include enough fees in transaction %d \n %s " , nValueOut - nValueIn , txCollateral . ToString ( ) ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
2015-09-09 20:34:52 +02:00
LogPrint ( " darksend " , " CDarksendPool::IsCollateralValid %s " , txCollateral . ToString ( ) ) ;
2014-12-09 02:17:57 +01:00
2015-07-30 15:44:18 +02:00
{
LOCK ( cs_main ) ;
CValidationState state ;
if ( ! AcceptableInputs ( mempool , state , txCollateral , true , NULL ) ) {
if ( fDebug ) LogPrintf ( " CDarksendPool::IsCollateralValid - didn't pass IsAcceptable \n " ) ;
return false ;
}
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
// Add a clients transaction to the pool
//
2016-01-24 05:21:14 +01:00
bool CDarksendPool : : AddEntry ( const std : : vector < CTxIn > & newInput , const CAmount & 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-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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 ) {
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " looking for vin -- %s \n " , in . ToString ( ) ) ;
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 ) {
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::AddEntry -- adding %s \n " , newInput [ 0 ] . ToString ( ) ) ;
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 ) {
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::AddScriptSig -- new sig %s \n " , newVin . scriptSig . ToString ( ) . substr ( 0 , 24 ) ) ;
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-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::AddScriptSig - already exists \n " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
}
}
if ( ! SignatureValid ( newVin . scriptSig , newVin ) ) {
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " CDarksendPool::AddScriptSig - Invalid Sig \n " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::AddScriptSig -- sig %s \n " , newVin . ToString ( ) ) ;
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-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarkSendPool::AddScriptSig -- adding to finalTransaction %s \n " , newVin . scriptSig . ToString ( ) . substr ( 0 , 24 ) ) ;
2015-04-06 17:39:48 +02:00
}
}
for ( unsigned int i = 0 ; i < entries . size ( ) ; i + + ) {
if ( entries [ i ] . AddSig ( newVin ) ) {
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarkSendPool::AddScriptSig -- adding %s \n " , newVin . scriptSig . ToString ( ) . substr ( 0 , 24 ) ) ;
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
//
2016-01-24 05:21:14 +01:00
void CDarksendPool : : SendDarksendDenominate ( std : : vector < CTxIn > & vin , std : : vector < CTxOut > & vout , CAmount amount ) {
2015-07-26 00:43:40 +02:00
if ( fMasterNode ) {
LogPrintf ( " CDarksendPool::SendDarksendDenominate() - Darksend from a Masternode is not supported currently. \n " ) ;
return ;
}
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)
2015-07-31 17:46:47 +02:00
// LogPrintf(" vout - %s\n", o.ToString());
2014-12-09 02:17:57 +01:00
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 ( ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
2014-12-09 02:17:57 +01:00
return ;
}
2015-05-30 05:46:29 +02:00
if ( ! CheckDiskSpace ( ) ) {
UnlockCoins ( ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
fEnableDarksend = false ;
LogPrintf ( " CDarksendPool::SendDarksendDenominate() - Not enough disk space, disabling Darksend. \n " ) ;
2014-12-09 02:17:57 +01:00
return ;
}
UpdateState ( POOL_STATUS_ACCEPTING_ENTRIES ) ;
2015-03-02 00:09:33 +01:00
LogPrintf ( " CDarksendPool::SendDarksendDenominate() - Added transaction to pool. \n " ) ;
2014-12-09 02:17:57 +01:00
ClearLastMessage ( ) ;
//check it against the memory pool to make sure it's valid
{
2016-01-24 05:21:14 +01:00
CAmount nValueOut = 0 ;
2014-12-09 02:17:57 +01:00
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 ) ;
2015-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " dsi -- tx in %s \n " , i . ToString ( ) ) ;
2014-12-09 02:17:57 +01:00
}
2015-07-31 17:46:47 +02:00
LogPrintf ( " Submitting tx %s \n " , tx . ToString ( ) ) ;
2015-03-02 00:09:33 +01:00
2015-08-07 06:08:37 +02:00
while ( true ) {
TRY_LOCK ( cs_main , lockMain ) ;
2015-08-08 23:48:09 +02:00
if ( ! lockMain ) { MilliSleep ( 50 ) ; continue ; }
2015-07-30 15:44:18 +02:00
if ( ! AcceptableInputs ( mempool , state , CTransaction ( tx ) , false , NULL , false , true ) ) {
2015-07-31 17:46:47 +02:00
LogPrintf ( " dsi -- transaction not valid! %s \n " , tx . ToString ( ) ) ;
2015-07-30 15:44:18 +02:00
UnlockCoins ( ) ;
SetNull ( ) ;
return ;
}
2015-08-07 06:08:37 +02:00
break ;
2014-12-09 02:17:57 +01:00
}
}
// store our entry for later use
CDarkSendEntry e ;
e . Add ( vin , amount , txCollateral , vout ) ;
2015-07-26 00:43:40 +02:00
entries . push_back ( e ) ;
2014-12-09 02:17:57 +01:00
2015-07-26 00:43:40 +02:00
RelayIn ( entries [ 0 ] . sev , entries [ 0 ] . amount , txCollateral , entries [ 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-08-28 22:04:14 +02:00
LogPrintf ( " CDarksendPool::SignFinalTransaction %s " , finalTransaction . ToString ( ) ) ;
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
2015-07-26 00:43:40 +02:00
BOOST_FOREACH ( const CDarkSendEntry e , entries ) {
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 ( ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
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-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " -- dss %d %d %s \n " , mine , ( int ) sigs . size ( ) , finalTransaction . vin [ mine ] . scriptSig . ToString ( ) ) ;
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-07-31 17:46:47 +02:00
LogPrint ( " darksend " , " CDarksendPool::Sign - txNew: \n %s " , finalTransaction . ToString ( ) ) ;
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-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " 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-09 02:17:57 +01:00
}
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 ( ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
2014-12-09 02:17:57 +01:00
} else {
LogPrintf ( " CompletedTransaction -- success \n " ) ;
UpdateState ( POOL_STATUS_SUCCESS ) ;
2015-03-02 00:09:33 +01:00
UnlockCoins ( ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
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
}
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-08-11 01:06:17 +02:00
bool CDarksendPool : : DoAutomaticDenominating ( bool fDryRun )
2014-12-09 02:17:57 +01:00
{
2015-08-07 06:08:37 +02:00
if ( ! fEnableDarksend ) return false ;
if ( fMasterNode ) return false ;
if ( state = = POOL_STATUS_ERROR | | state = = POOL_STATUS_SUCCESS ) return false ;
if ( GetEntriesCount ( ) > 0 ) {
strAutoDenomResult = _ ( " Mixing in progress... " ) ;
return false ;
}
2015-08-03 21:53:00 +02:00
TRY_LOCK ( cs_darksend , lockDS ) ;
if ( ! lockDS ) {
strAutoDenomResult = _ ( " Lock is already in place. " ) ;
return false ;
}
2015-07-26 01:24:19 +02:00
if ( ! masternodeSync . IsBlockchainSynced ( ) ) {
2015-07-26 00:43:40 +02:00
strAutoDenomResult = _ ( " Can't mix while sync in progress. " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
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-09-15 19:40:36 +02:00
if ( ! fDarksendMultiSession & & chainActive . Tip ( ) - > nHeight - cachedLastSuccess < minBlockSpacing ) {
2015-08-11 07:09:56 +02:00
LogPrintf ( " CDarksendPool::DoAutomaticDenominating - Last successful Darksend action was too recent \n " ) ;
strAutoDenomResult = _ ( " Last successful Darksend action was too recent. " ) ;
return false ;
}
2014-12-09 02:17:57 +01:00
2015-02-23 21:01:21 +01:00
if ( mnodeman . size ( ) = = 0 ) {
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " CDarksendPool::DoAutomaticDenominating - No Masternodes detected \n " ) ;
2015-03-05 09:10:15 +01:00
strAutoDenomResult = _ ( " No Masternodes detected. " ) ;
2014-12-28 02:08:45 +01:00
return false ;
}
2014-12-09 02:17:57 +01:00
// ** find the coins we'll use
std : : vector < CTxIn > vCoins ;
2015-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-11-06 18:23:19 +01:00
CAmount nLowestDenom = darkSendDenominations [ darkSendDenominations . size ( ) - 1 ] ;
2015-01-21 07:09:04 +01:00
2015-11-06 18:23:19 +01:00
// if there are no confirmed DS collateral inputs yet
2015-01-27 05:13:34 +01:00
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
2016-01-31 14:23:02 +01:00
CAmount nBalanceNeedsAnonymized = nAnonymizeDashAmount * 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-11-06 18:23:19 +01:00
// try to overshoot target DS balance up to nLowestDenom
nBalanceNeedsAnonymized + = nLowestDenom ;
2015-04-30 00:06:24 +02:00
CAmount nAnonymizableBalance = pwalletMain - > GetAnonymizableBalance ( ) ;
2014-12-09 02:17:57 +01:00
2015-11-06 18:23:19 +01:00
// anonymizable balance is way too small
if ( nAnonymizableBalance < nLowestDenom )
2015-01-21 07:09:04 +01:00
{
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-11-06 18:23:19 +01:00
// not enough funds to anonymze amount we want, try the max we can
if ( nBalanceNeedsAnonymized > nAnonymizableBalance ) nBalanceNeedsAnonymized = nAnonymizableBalance ;
2015-06-23 17:08:53 +02:00
LogPrint ( " darksend " , " DoAutomaticDenominating : nLowestDenom=%d, nBalanceNeedsAnonymized=%d \n " , nLowestDenom , nBalanceNeedsAnonymized ) ;
2015-01-25 00:57:55 +01:00
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-07-26 01:24:19 +02:00
nOnlyDenominatedBalance = pwalletMain - > GetDenominatedBalance ( true ) + pwalletMain - > GetDenominatedBalance ( ) - pwalletMain - > GetAnonymizedBalance ( ) ;
2015-04-30 00:06:24 +02:00
nBalanceNeedsDenominated = nBalanceNeedsAnonymized - nOnlyDenominatedBalance ;
if ( nBalanceNeedsDenominated > nValueIn ) nBalanceNeedsDenominated = nValueIn ;
2015-08-11 01:06:17 +02:00
if ( nBalanceNeedsDenominated < nLowestDenom ) return false ; // most likely we just waiting for denoms to confirm
2015-04-30 00:06:24 +02:00
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-07-26 01:24:19 +02:00
nOnlyDenominatedBalance = pwalletMain - > GetDenominatedBalance ( true ) + pwalletMain - > GetDenominatedBalance ( ) - pwalletMain - > GetAnonymizedBalance ( ) ;
2015-04-30 00:06:24 +02:00
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
2015-08-16 02:29:16 +02:00
if ( ! pwalletMain - > HasCollateralInputs ( ) ) return ! pwalletMain - > HasCollateralInputs ( false ) & & 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 ( ) ;
2015-07-26 00:43:40 +02:00
SetNull ( ) ;
2015-05-30 05:46:29 +02:00
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
2015-09-15 19:40:36 +02:00
if ( ! fDarksendMultiSession & & pwalletMain - > GetDenominatedBalance ( true ) > 0 ) { //get denominated unconfirmed inputs
2015-08-13 00:54:21 +02:00
LogPrintf ( " DoAutomaticDenominating -- Found unconfirmed denominated outputs, will wait till they confirm to continue. \n " ) ;
strAutoDenomResult = _ ( " Found unconfirmed denominated outputs, will wait till they confirm to continue. " ) ;
return false ;
}
2014-12-09 02:17:57 +01:00
2015-11-06 18:23:19 +01:00
//check our collateral and create new if needed
2015-05-30 05:46:29 +02:00
std : : string strReason ;
CValidationState state ;
if ( txCollateral = = CMutableTransaction ( ) ) {
if ( ! pwalletMain - > CreateCollateralTransaction ( txCollateral , strReason ) ) {
2015-07-31 17:46:47 +02:00
LogPrintf ( " % -- create collateral error:%s \n " , __func__ , strReason ) ;
2015-05-30 05:46:29 +02:00
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 ) ) {
2015-07-31 17:46:47 +02:00
LogPrintf ( " %s -- create collateral error: %s \n " , __func__ , strReason ) ;
2015-05-30 05:46:29 +02:00
return false ;
}
2015-04-07 18:41:31 +02:00
}
}
2015-08-11 07:09:56 +02:00
//if we've used 90% of the Masternode list then drop all the oldest first
int nThreshold = ( int ) ( mnodeman . CountEnabled ( MIN_POOL_PEER_PROTO_VERSION ) * 0.9 ) ;
LogPrint ( " darksend " , " Checking vecMasternodesUsed size %d threshold %d \n " , ( int ) vecMasternodesUsed . size ( ) , nThreshold ) ;
while ( ( int ) vecMasternodesUsed . size ( ) > nThreshold ) {
vecMasternodesUsed . erase ( vecMasternodesUsed . begin ( ) ) ;
LogPrint ( " darksend " , " vecMasternodesUsed size %d threshold %d \n " , ( int ) vecMasternodesUsed . size ( ) , nThreshold ) ;
}
2016-01-24 20:22:13 +01:00
// don't use the queues all of the time for mixing unless we are a liquidity provider
if ( nLiquidityProvider | | nUseQueue > 33 ) {
2014-12-09 02:17:57 +01:00
// 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-08-22 05:36:21 +02:00
bool fUsed = 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 ) {
if ( dsq . vin = = usedVin ) {
2015-08-22 05:36:21 +02:00
fUsed = true ;
break ;
2014-12-09 02:17:57 +01:00
}
}
2015-08-22 05:36:21 +02:00
if ( fUsed ) continue ;
2014-12-09 02:17:57 +01:00
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
2015-08-04 22:51:16 +02:00
CNode * pnode = ConnectNode ( ( CAddress ) addr , NULL , true ) ;
if ( pnode ! = NULL )
{
CMasternode * pmn = mnodeman . Find ( dsq . vin ) ;
if ( pmn = = NULL )
2014-12-09 02:17:57 +01:00
{
2015-08-04 22:51:16 +02:00
LogPrintf ( " DoAutomaticDenominating --- dsq vin %s is not in masternode list! " , dsq . vin . ToString ( ) ) ;
continue ;
2014-12-09 02:17:57 +01:00
}
2015-08-04 22:51:16 +02:00
pSubmittedToMasternode = pmn ;
vecMasternodesUsed . push_back ( dsq . vin ) ;
sessionDenom = dsq . nDenom ;
pnode - > PushMessage ( " dsa " , sessionDenom , txCollateral ) ;
LogPrintf ( " DoAutomaticDenominating --- connected (from queue), sending dsa for %d - %s \n " , sessionDenom , pnode - > addr . ToString ( ) ) ;
strAutoDenomResult = _ ( " Mixing in progress... " ) ;
dsq . time = 0 ; //remove node
return true ;
2014-12-09 02:17:57 +01:00
} 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
2015-08-22 05:36:21 +02:00
continue ;
2014-12-09 02:17:57 +01:00
}
}
}
2015-09-25 01:16:49 +02:00
// do not initiate queue if we are a liquidity proveder to avoid useless inter-mixing
if ( nLiquidityProvider ) return false ;
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-07-29 17:11:43 +02:00
CMasternode * pmn = mnodeman . FindRandomNotInVec ( vecMasternodesUsed , MIN_POOL_PEER_PROTO_VERSION ) ;
2015-02-26 02:55:27 +01:00
if ( pmn = = NULL )
{
2015-07-29 17:11:43 +02:00
LogPrintf ( " DoAutomaticDenominating --- Can't find random masternode! \n " ) ;
strAutoDenomResult = _ ( " Can't find random Masternode. " ) ;
2015-02-26 02:55:27 +01:00
return false ;
}
2014-12-09 02:17:57 +01:00
2015-02-26 02:55:27 +01:00
if ( pmn - > nLastDsq ! = 0 & &
2015-07-19 01:20:48 +02:00
pmn - > nLastDsq + mnodeman . CountEnabled ( 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-07-31 17:46:47 +02:00
LogPrintf ( " DoAutomaticDenominating -- attempt %d connection to Masternode %s \n " , i , pmn - > addr . ToString ( ) ) ;
2015-08-04 22:51:16 +02:00
CNode * pnode = ConnectNode ( ( CAddress ) pmn - > addr , NULL , true ) ;
if ( pnode ! = NULL ) {
pSubmittedToMasternode = pmn ;
vecMasternodesUsed . push_back ( pmn - > vin ) ;
std : : vector < CAmount > vecAmounts ;
pwalletMain - > ConvertList ( vCoins , vecAmounts ) ;
2015-08-10 01:28:43 +02:00
// try to get a single random denom out of vecAmounts
2015-08-04 22:51:16 +02:00
while ( sessionDenom = = 0 )
2015-08-10 01:28:43 +02:00
sessionDenom = GetDenominationsByAmounts ( vecAmounts ) ;
2015-08-04 22:51:16 +02:00
pnode - > PushMessage ( " dsa " , sessionDenom , txCollateral ) ;
LogPrintf ( " DoAutomaticDenominating --- connected, sending dsa for %d \n " , sessionDenom ) ;
strAutoDenomResult = _ ( " Mixing in progress... " ) ;
return true ;
2014-12-09 02:17:57 +01:00
} else {
2015-08-22 05:36:21 +02:00
vecMasternodesUsed . push_back ( pmn - > vin ) ; // postpone MN we wasn't able to connect to
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... " ) ;
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
{
2015-09-09 07:00:30 +02:00
std : : string strError = " " ;
// Submit transaction to the pool if we get here
// Try to use only inputs with the same number of rounds starting from lowest number of rounds possible
for ( int i = 0 ; i < nDarksendRounds ; i + + ) {
strError = pwalletMain - > PrepareDarksendDenominate ( i , i + 1 ) ;
LogPrintf ( " DoAutomaticDenominating : Running Darksend denominate for %d rounds. Return '%s' \n " , i , strError ) ;
if ( strError = = " " ) return true ;
}
2014-12-25 20:21:35 +01:00
2015-09-09 07:00:30 +02:00
// We failed? That's strange but let's just make final attempt and try to mix everything
strError = pwalletMain - > PrepareDarksendDenominate ( 0 , nDarksendRounds ) ;
LogPrintf ( " DoAutomaticDenominating : Running Darksend denominate for all rounds. Return '%s' \n " , strError ) ;
2014-12-09 02:17:57 +01:00
if ( strError = = " " ) return true ;
2015-09-09 07:00:30 +02:00
// Should never actually get here but just in case
2014-12-30 01:09:34 +01:00
strAutoDenomResult = strError ;
2015-07-31 17:46:47 +02:00
LogPrintf ( " DoAutomaticDenominating : Error running denominate, %s \n " , strError ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
// 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 ;
2016-01-24 05:21:14 +01:00
CAmount nFeeRet = 0 ;
2014-12-09 02:17:57 +01:00
std : : string strFail = " " ;
2016-01-24 05:21:14 +01:00
vector < pair < CScript , CAmount > > 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-08-16 02:26:20 +02:00
nFeeRet , strFail , coinControl , ONLY_NONDENOMINATED_NOT1000IFMN ) ;
2014-12-09 02:17:57 +01:00
if ( ! success ) {
2015-08-16 02:26:20 +02:00
// if we failed (most likeky not enough funds), try to use all coins instead -
2015-01-27 05:39:27 +01:00
// MN-like funds should not be touched in any case and we can't mix denominated without collaterals anyway
2015-08-16 02:26:20 +02:00
LogPrintf ( " MakeCollateralAmounts: ONLY_NONDENOMINATED_NOT1000IFMN Error - %s \n " , strFail ) ;
2015-06-22 19:59:27 +02:00
success = pwalletMain - > CreateTransaction ( vecSend , wtx , reservekeyChange ,
2015-08-16 02:26:20 +02:00
nFeeRet , strFail , coinControl , ONLY_NOT1000IFMN ) ;
2015-01-27 05:39:27 +01:00
if ( ! success ) {
2015-08-16 02:26:20 +02:00
LogPrintf ( " MakeCollateralAmounts: ONLY_NOT1000IFMN Error - %s \n " , strFail ) ;
2015-06-22 19:59:27 +02:00
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
2016-01-24 05:21:14 +01:00
bool CDarksendPool : : CreateDenominated ( CAmount nTotalValue )
2015-01-15 15:41:56 +01:00
{
CWalletTx wtx ;
2016-01-24 05:21:14 +01:00
CAmount nFeeRet = 0 ;
2015-01-15 15:41:56 +01:00
std : : string strFail = " " ;
2016-01-24 05:21:14 +01:00
vector < pair < CScript , CAmount > > vecSend ;
CAmount nValueLeft = nTotalValue ;
2015-01-15 15:41:56 +01:00
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 ************ /
2015-12-02 23:12:16 +01:00
2016-01-24 05:21:14 +01:00
BOOST_REVERSE_FOREACH ( CAmount v , darkSendDenominations ) {
2015-12-02 23:12:16 +01:00
// Note: denoms are skipped if there are already DENOMS_COUNT_MAX of them
// check skipped denoms
if ( IsDenomSkipped ( v ) ) continue ;
// find new denoms to skip if any (ignore the largest one)
if ( v ! = darkSendDenominations [ 0 ] & & pwalletMain - > CountInputsWithAmount ( v ) > DENOMS_COUNT_MAX ) {
strAutoDenomResult = strprintf ( _ ( " Too many %f denominations, removing. " ) , ( float ) v / COIN ) ;
LogPrintf ( " DoAutomaticDenominating : %s \n " , strAutoDenomResult ) ;
darkSendDenominationsSkipped . push_back ( v ) ;
continue ;
}
2015-01-15 15:41:56 +01:00
int nOutputs = 0 ;
// add each output up to 10 times until it can't be added again
2015-11-06 18:23:19 +01:00
while ( nValueLeft - v > = 0 & & 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-08-16 02:26:20 +02:00
nFeeRet , strFail , coinControl , ONLY_NONDENOMINATED_NOT1000IFMN ) ;
2015-01-15 15:41:56 +01:00
if ( ! success ) {
2015-07-31 17:46:47 +02:00
LogPrintf ( " CreateDenominated: Error - %s \n " , strFail ) ;
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-07-31 17:46:47 +02:00
LogPrintf ( " CreateDenominated: tx %s \n " , wtx . GetHash ( ) . GetHex ( ) ) ;
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 ) ) ;
if ( GetDenominations ( vout ) ! = GetDenominations ( v . vout ) ) return false ;
}
return true ;
}
2016-01-24 05:21:14 +01:00
bool CDarksendPool : : IsCompatibleWithSession ( CAmount 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-08-05 05:02:54 +02:00
LogPrint ( " darksend " , " 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 ( ) ;
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-08-10 01:28:43 +02:00
int CDarksendPool : : GetDenominations ( const std : : vector < CTxOut > & vout , bool fSingleRandomDenom ) {
2016-01-24 05:21:14 +01:00
std : : vector < pair < CAmount , int > > denomUsed ;
2014-12-09 02:17:57 +01:00
// make a list of denominations, with zero uses
2016-01-24 05:21:14 +01:00
BOOST_FOREACH ( CAmount d , darkSendDenominations )
2014-12-09 02:17:57 +01:00
denomUsed . push_back ( make_pair ( d , 0 ) ) ;
// look for denominations and update uses to 1
BOOST_FOREACH ( CTxOut out , vout ) {
bool found = false ;
2016-01-24 05:21:14 +01:00
BOOST_FOREACH ( PAIRTYPE ( CAmount , int ) & s , denomUsed ) {
2014-12-09 02:17:57 +01:00
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
2016-01-24 05:21:14 +01:00
BOOST_FOREACH ( PAIRTYPE ( CAmount , int ) & s , denomUsed ) {
2015-08-10 01:28:43 +02:00
int bit = ( fSingleRandomDenom ? rand ( ) % 2 : 1 ) * s . second ;
denom | = bit < < c + + ;
if ( fSingleRandomDenom & & bit ) break ; // use just one random denomination
}
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
2016-01-24 05:21:14 +01:00
int CDarksendPool : : GetDenominationsByAmounts ( std : : vector < CAmount > & vecAmount ) {
2014-12-09 02:17:57 +01:00
CScript e = CScript ( ) ;
std : : vector < CTxOut > vout1 ;
// Make outputs by looping through denominations, from small to large
2016-01-24 05:21:14 +01:00
BOOST_REVERSE_FOREACH ( CAmount v , vecAmount ) {
2014-12-09 02:17:57 +01:00
CTxOut o ( v , e ) ;
vout1 . push_back ( o ) ;
}
2015-08-10 01:28:43 +02:00
return GetDenominations ( vout1 , true ) ;
2014-12-09 02:17:57 +01:00
}
2016-01-24 05:21:14 +01:00
int CDarksendPool : : GetDenominationsByAmount ( CAmount nAmount , int nDenomTarget ) {
2014-12-09 02:17:57 +01:00
CScript e = CScript ( ) ;
2016-01-24 05:21:14 +01:00
CAmount nValueLeft = nAmount ;
2014-12-09 02:17:57 +01:00
std : : vector < CTxOut > vout1 ;
// Make outputs by looping through denominations, from small to large
2016-01-24 05:21:14 +01:00
BOOST_REVERSE_FOREACH ( CAmount 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 ( ) )
2015-07-30 18:00:28 +02:00
LogPrintf ( " CDarkSendSigner::VerifyMessage -- keys don't match: %s %s \n " , pubkey2 . GetID ( ) . ToString ( ) , pubkey . GetID ( ) . ToString ( ) ) ;
2015-01-25 22:18:26 +01:00
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-07-31 17:46:47 +02:00
LogPrintf ( " CDarksendQueue():Relay - ERROR: Invalid Masternodeprivkey: '%s' \n " , errorMessage ) ;
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 ) ;
}
}
2016-01-24 05:21:14 +01:00
void CDarksendPool : : RelayIn ( const std : : vector < CTxDSIn > & vin , const CAmount & nAmount , const CTransaction & txCollateral , const std : : vector < CTxDSOut > & vout )
2015-03-02 00:09:33 +01:00
{
2015-08-04 22:51:16 +02:00
if ( ! pSubmittedToMasternode ) return ;
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-08-04 22:51:16 +02:00
CNode * pnode = FindNode ( pSubmittedToMasternode - > addr ) ;
if ( pnode ! = NULL ) {
2015-07-31 17:46:47 +02:00
LogPrintf ( " RelayIn - found master, relaying message - %s \n " , pnode - > addr . ToString ( ) ) ;
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 )
{
MilliSleep ( 1000 ) ;
//LogPrintf("ThreadCheckDarkSendPool::check timeout\n");
2015-03-04 19:17:30 +01:00
2015-07-26 00:43:40 +02:00
// try to sync from all available nodes, one step at a time
2015-07-15 04:44:58 +02:00
masternodeSync . Process ( ) ;
2015-07-26 01:24:19 +02:00
if ( masternodeSync . IsBlockchainSynced ( ) ) {
2015-07-23 04:19:37 +02:00
c + + ;
// check if we should activate or ping every few minutes,
// start right after sync is considered to be done
2015-07-19 17:49:46 +02:00
if ( c % MASTERNODE_PING_SECONDS = = 1 ) activeMasternode . ManageStatus ( ) ;
2014-12-09 02:17:57 +01:00
2015-07-14 08:10:18 +02:00
if ( c % 60 = = 0 )
{
2015-08-05 00:49:34 +02:00
mnodeman . CheckAndRemove ( ) ;
2015-07-14 08:10:18 +02:00
mnodeman . ProcessMasternodeConnections ( ) ;
2016-02-04 20:29:09 +01:00
mnpayments . CleanPaymentList ( ) ;
2015-07-14 08:10:18 +02:00
CleanTransactionLocksList ( ) ;
}
2015-08-18 22:46:47 +02:00
//if(c % MASTERNODES_DUMP_SECONDS == 0) DumpMasternodes();
2015-07-14 08:10:18 +02:00
darkSendPool . CheckTimeout ( ) ;
darkSendPool . CheckForCompleteQueue ( ) ;
2015-08-11 01:06:17 +02:00
if ( darkSendPool . GetState ( ) = = POOL_STATUS_IDLE & & c % 15 = = 0 ) {
2015-07-14 08:10:18 +02:00
darkSendPool . DoAutomaticDenominating ( ) ;
}
2014-12-09 02:17:57 +01:00
}
}
}