2017-05-05 13:26:27 +02:00
// Copyright (c) 2014-2017 The Dash Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# include "privatesend.h"
# include "activemasternode.h"
# include "consensus/validation.h"
# include "masternode-payments.h"
# include "masternode-sync.h"
# include "masternodeman.h"
# include "messagesigner.h"
2016-11-25 20:01:56 +01:00
# include "netmessagemaker.h"
2017-05-05 13:26:27 +02:00
# include "script/sign.h"
# include "txmempool.h"
# include "util.h"
# include "utilmoneystr.h"
2018-07-12 11:02:20 +02:00
# include <string>
2017-05-05 13:26:27 +02:00
2018-10-25 16:31:32 +02:00
bool CPrivateSendEntry : : AddScriptSig ( const CTxIn & txin )
2017-05-05 13:26:27 +02:00
{
2018-02-06 12:09:33 +01:00
for ( auto & txdsin : vecTxDSIn ) {
2018-11-05 10:29:07 +01:00
if ( txdsin . prevout = = txin . prevout & & txdsin . nSequence = = txin . nSequence ) {
if ( txdsin . fHasSig ) return false ;
2017-05-05 13:26:27 +02:00
txdsin . scriptSig = txin . scriptSig ;
txdsin . fHasSig = true ;
return true ;
}
}
return false ;
}
2018-10-25 16:31:32 +02:00
uint256 CPrivateSendQueue : : GetSignatureHash ( ) const
2018-02-16 15:54:53 +01:00
{
2018-10-11 16:32:51 +02:00
// Remove after migration to 70211
{
2018-11-05 10:29:07 +01:00
masternode_info_t mnInfo ;
mnodeman . GetMasternodeInfo ( masternodeOutpoint , mnInfo ) ;
return SerializeHash ( * this , SER_GETHASH , mnInfo . nProtocolVersion ) ;
2018-10-11 16:32:51 +02:00
}
// END remove, replace with the code below
// return SerializeHash(*this);
2018-02-16 15:54:53 +01:00
}
2018-10-25 16:31:32 +02:00
bool CPrivateSendQueue : : Sign ( )
2017-05-05 13:26:27 +02:00
{
2018-11-05 10:29:07 +01:00
if ( ! fMasternodeMode ) return false ;
2017-05-05 13:26:27 +02:00
2018-02-16 15:54:53 +01:00
std : : string strError = " " ;
2018-10-21 21:45:16 +02:00
if ( deterministicMNManager - > IsDeterministicMNsSporkActive ( ) ) {
uint256 hash = GetSignatureHash ( ) ;
CBLSSignature sig = activeMasternodeInfo . blsKeyOperator - > Sign ( hash ) ;
sig . GetBuf ( vchSig ) ;
} else if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
2018-02-16 15:54:53 +01:00
uint256 hash = GetSignatureHash ( ) ;
2018-10-21 21:45:16 +02:00
if ( ! CHashSigner : : SignHash ( hash , activeMasternodeInfo . legacyKeyOperator , vchSig ) ) {
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendQueue::Sign -- SignHash() failed \n " ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
2018-10-21 21:45:16 +02:00
if ( ! CHashSigner : : VerifyHash ( hash , activeMasternodeInfo . legacyKeyIDOperator , vchSig , strError ) ) {
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendQueue::Sign -- VerifyHash() failed, error: %s \n " , strError ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
2018-02-15 15:44:22 +01:00
} else {
2018-02-16 15:54:53 +01:00
std : : string strMessage = CTxIn ( masternodeOutpoint ) . ToString ( ) +
2018-11-05 10:29:07 +01:00
std : : to_string ( nDenom ) +
std : : to_string ( nTime ) +
std : : to_string ( fReady ) ;
2018-02-16 15:54:53 +01:00
2018-11-05 10:29:07 +01:00
if ( ! CMessageSigner : : SignMessage ( strMessage , vchSig , activeMasternodeInfo . legacyKeyOperator ) ) {
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendQueue::Sign -- SignMessage() failed, %s \n " , ToString ( ) ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
2017-05-05 13:26:27 +02:00
2018-11-05 10:29:07 +01:00
if ( ! CMessageSigner : : VerifyMessage ( activeMasternodeInfo . legacyKeyIDOperator , vchSig , strMessage , strError ) ) {
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendQueue::Sign -- VerifyMessage() failed, error: %s \n " , strError ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
2017-06-30 20:30:16 +02:00
}
2018-02-16 15:54:53 +01:00
return true ;
2017-06-30 20:30:16 +02:00
}
2018-10-25 16:31:32 +02:00
bool CPrivateSendQueue : : CheckSignature ( const CKeyID & keyIDOperator , const CBLSPublicKey & blsPubKey ) const
2017-06-30 20:30:16 +02:00
{
std : : string strError = " " ;
2018-10-21 21:45:16 +02:00
if ( deterministicMNManager - > IsDeterministicMNsSporkActive ( ) ) {
uint256 hash = GetSignatureHash ( ) ;
2018-02-16 15:54:53 +01:00
2018-10-21 21:45:16 +02:00
CBLSSignature sig ;
sig . SetBuf ( vchSig ) ;
if ( ! sig . IsValid ( ) | | ! sig . VerifyInsecure ( blsPubKey , hash ) ) {
LogPrintf ( " CTxLockVote::CheckSignature -- VerifyInsecure() failed \n " ) ;
return false ;
}
} else if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
2018-02-16 15:54:53 +01:00
uint256 hash = GetSignatureHash ( ) ;
2017-06-30 20:30:16 +02:00
2018-08-31 15:31:59 +02:00
if ( ! CHashSigner : : VerifyHash ( hash , keyIDOperator , vchSig , strError ) ) {
2018-02-16 15:54:53 +01:00
// we don't care about queues with old signature format
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendQueue::CheckSignature -- VerifyHash() failed, error: %s \n " , strError ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
} else {
std : : string strMessage = CTxIn ( masternodeOutpoint ) . ToString ( ) +
2018-11-05 10:29:07 +01:00
std : : to_string ( nDenom ) +
std : : to_string ( nTime ) +
std : : to_string ( fReady ) ;
2018-02-16 15:54:53 +01:00
2018-11-05 10:29:07 +01:00
if ( ! CMessageSigner : : VerifyMessage ( keyIDOperator , vchSig , strMessage , strError ) ) {
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendQueue::CheckSignature -- Got bad Masternode queue signature: %s; error: %s \n " , ToString ( ) , strError ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
2017-06-30 20:30:16 +02:00
}
return true ;
}
2018-10-25 16:31:32 +02:00
bool CPrivateSendQueue : : Relay ( CConnman & connman )
2017-06-30 20:30:16 +02:00
{
2018-02-06 12:09:33 +01:00
connman . ForEachNode ( [ & connman , this ] ( CNode * pnode ) {
2016-11-25 20:01:56 +01:00
CNetMsgMaker msgMaker ( pnode - > GetSendVersion ( ) ) ;
if ( pnode - > nVersion > = MIN_PRIVATESEND_PEER_PROTO_VERSION )
connman . PushMessage ( pnode , msgMaker . Make ( NetMsgType : : DSQUEUE , ( * this ) ) ) ;
2018-02-06 12:09:33 +01:00
} ) ;
2017-06-30 20:30:16 +02:00
return true ;
2017-05-05 13:26:27 +02:00
}
2018-10-25 16:31:32 +02:00
uint256 CPrivateSendBroadcastTx : : GetSignatureHash ( ) const
2018-02-16 15:54:53 +01:00
{
return SerializeHash ( * this ) ;
}
2018-10-25 16:31:32 +02:00
bool CPrivateSendBroadcastTx : : Sign ( )
2017-06-30 20:30:16 +02:00
{
2018-11-05 10:29:07 +01:00
if ( ! fMasternodeMode ) return false ;
2017-06-30 20:30:16 +02:00
2018-02-16 15:54:53 +01:00
std : : string strError = " " ;
2018-10-21 21:45:16 +02:00
if ( deterministicMNManager - > IsDeterministicMNsSporkActive ( ) ) {
uint256 hash = GetSignatureHash ( ) ;
CBLSSignature sig = activeMasternodeInfo . blsKeyOperator - > Sign ( hash ) ;
sig . GetBuf ( vchSig ) ;
} else if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
2018-02-16 15:54:53 +01:00
uint256 hash = GetSignatureHash ( ) ;
2018-10-21 21:45:16 +02:00
if ( ! CHashSigner : : SignHash ( hash , activeMasternodeInfo . legacyKeyOperator , vchSig ) ) {
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendBroadcastTx::Sign -- SignHash() failed \n " ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
2018-10-21 21:45:16 +02:00
if ( ! CHashSigner : : VerifyHash ( hash , activeMasternodeInfo . legacyKeyIDOperator , vchSig , strError ) ) {
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendBroadcastTx::Sign -- VerifyHash() failed, error: %s \n " , strError ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
} else {
2018-07-12 11:02:20 +02:00
std : : string strMessage = tx - > GetHash ( ) . ToString ( ) + std : : to_string ( sigTime ) ;
2018-02-16 15:54:53 +01:00
2018-11-05 10:29:07 +01:00
if ( ! CMessageSigner : : SignMessage ( strMessage , vchSig , activeMasternodeInfo . legacyKeyOperator ) ) {
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendBroadcastTx::Sign -- SignMessage() failed \n " ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
2017-06-30 20:30:16 +02:00
2018-11-05 10:29:07 +01:00
if ( ! CMessageSigner : : VerifyMessage ( activeMasternodeInfo . legacyKeyIDOperator , vchSig , strMessage , strError ) ) {
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendBroadcastTx::Sign -- VerifyMessage() failed, error: %s \n " , strError ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
2017-06-30 20:30:16 +02:00
}
2018-02-16 15:54:53 +01:00
return true ;
2017-06-30 20:30:16 +02:00
}
2018-10-25 16:31:32 +02:00
bool CPrivateSendBroadcastTx : : CheckSignature ( const CKeyID & keyIDOperator , const CBLSPublicKey & blsPubKey ) const
2017-06-30 20:30:16 +02:00
{
std : : string strError = " " ;
2018-10-21 21:45:16 +02:00
if ( deterministicMNManager - > IsDeterministicMNsSporkActive ( ) ) {
uint256 hash = GetSignatureHash ( ) ;
CBLSSignature sig ;
sig . SetBuf ( vchSig ) ;
if ( ! sig . IsValid ( ) | | ! sig . VerifyInsecure ( blsPubKey , hash ) ) {
LogPrintf ( " CTxLockVote::CheckSignature -- VerifyInsecure() failed \n " ) ;
return false ;
}
} else if ( sporkManager . IsSporkActive ( SPORK_6_NEW_SIGS ) ) {
2018-02-16 15:54:53 +01:00
uint256 hash = GetSignatureHash ( ) ;
2018-08-31 15:31:59 +02:00
if ( ! CHashSigner : : VerifyHash ( hash , keyIDOperator , vchSig , strError ) ) {
2018-02-16 15:54:53 +01:00
// we don't care about dstxes with old signature format
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendBroadcastTx::CheckSignature -- VerifyHash() failed, error: %s \n " , strError ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
} else {
2018-07-12 11:02:20 +02:00
std : : string strMessage = tx - > GetHash ( ) . ToString ( ) + std : : to_string ( sigTime ) ;
2018-02-16 15:54:53 +01:00
2018-11-05 10:29:07 +01:00
if ( ! CMessageSigner : : VerifyMessage ( keyIDOperator , vchSig , strMessage , strError ) ) {
2018-10-25 16:31:32 +02:00
LogPrintf ( " CPrivateSendBroadcastTx::CheckSignature -- Got bad dstx signature, error: %s \n " , strError ) ;
2018-02-16 15:54:53 +01:00
return false ;
}
2017-06-30 20:30:16 +02:00
}
return true ;
}
2018-10-25 16:31:32 +02:00
bool CPrivateSendBroadcastTx : : IsExpired ( int nHeight )
2017-07-10 16:42:09 +02:00
{
// expire confirmed DSTXes after ~1h since confirmation
return ( nConfirmedHeight ! = - 1 ) & & ( nHeight - nConfirmedHeight > 24 ) ;
}
2018-09-04 12:54:59 +02:00
void CPrivateSendBaseSession : : SetNull ( )
2017-05-05 13:26:27 +02:00
{
// Both sides
2018-10-25 16:31:32 +02:00
LOCK ( cs_privatesend ) ;
2017-05-05 13:26:27 +02:00
nState = POOL_STATE_IDLE ;
nSessionID = 0 ;
nSessionDenom = 0 ;
vecEntries . clear ( ) ;
finalMutableTransaction . vin . clear ( ) ;
finalMutableTransaction . vout . clear ( ) ;
2018-02-12 13:47:53 +01:00
nTimeLastSuccessfulStep = GetTime ( ) ;
2017-05-05 13:26:27 +02:00
}
2018-09-04 12:54:59 +02:00
void CPrivateSendBaseManager : : SetNull ( )
2017-12-04 07:06:07 +01:00
{
2018-09-04 12:54:59 +02:00
LOCK ( cs_vecqueue ) ;
2018-10-25 16:31:32 +02:00
vecPrivateSendQueue . clear ( ) ;
2018-09-04 12:54:59 +02:00
}
void CPrivateSendBaseManager : : CheckQueue ( )
{
TRY_LOCK ( cs_vecqueue , lockDS ) ;
2018-11-05 10:29:07 +01:00
if ( ! lockDS ) return ; // it's ok to fail here, we run this quite frequently
2017-12-04 07:06:07 +01:00
// check mixing queue objects for timeouts
2018-10-25 16:31:32 +02:00
std : : vector < CPrivateSendQueue > : : iterator it = vecPrivateSendQueue . begin ( ) ;
2018-11-05 10:29:07 +01:00
while ( it ! = vecPrivateSendQueue . end ( ) ) {
if ( ( * it ) . IsExpired ( ) ) {
2018-09-04 12:54:59 +02:00
LogPrint ( " privatesend " , " CPrivateSendBaseManager::%s -- Removing expired queue (%s) \n " , __func__ , ( * it ) . ToString ( ) ) ;
2018-10-25 16:31:32 +02:00
it = vecPrivateSendQueue . erase ( it ) ;
2018-11-05 10:29:07 +01:00
} else
+ + it ;
2017-12-04 07:06:07 +01:00
}
}
2018-10-25 16:31:32 +02:00
bool CPrivateSendBaseManager : : GetQueueItemAndTry ( CPrivateSendQueue & dsqRet )
2018-09-04 12:54:59 +02:00
{
TRY_LOCK ( cs_vecqueue , lockDS ) ;
2018-11-05 10:29:07 +01:00
if ( ! lockDS ) return false ; // it's ok to fail here, we run this quite frequently
2018-09-04 12:54:59 +02:00
2018-10-25 16:31:32 +02:00
for ( auto & dsq : vecPrivateSendQueue ) {
2018-09-04 12:54:59 +02:00
// only try each queue once
2018-11-05 10:29:07 +01:00
if ( dsq . fTried | | dsq . IsExpired ( ) ) continue ;
2018-09-04 12:54:59 +02:00
dsq . fTried = true ;
dsqRet = dsq ;
return true ;
}
return false ;
}
std : : string CPrivateSendBaseSession : : GetStateString ( ) const
2017-05-05 13:26:27 +02:00
{
2018-11-05 10:29:07 +01:00
switch ( nState ) {
case POOL_STATE_IDLE :
return " IDLE " ;
case POOL_STATE_QUEUE :
return " QUEUE " ;
case POOL_STATE_ACCEPTING_ENTRIES :
return " ACCEPTING_ENTRIES " ;
case POOL_STATE_SIGNING :
return " SIGNING " ;
case POOL_STATE_ERROR :
return " ERROR " ;
case POOL_STATE_SUCCESS :
return " SUCCESS " ;
default :
return " UNKNOWN " ;
2017-05-05 13:26:27 +02:00
}
}
2017-06-30 20:30:16 +02:00
// Definitions for static data members
std : : vector < CAmount > CPrivateSend : : vecStandardDenominations ;
2018-10-25 16:31:32 +02:00
std : : map < uint256 , CPrivateSendBroadcastTx > CPrivateSend : : mapDSTX ;
2017-06-30 20:30:16 +02:00
CCriticalSection CPrivateSend : : cs_mapdstx ;
void CPrivateSend : : InitStandardDenominations ( )
{
vecStandardDenominations . clear ( ) ;
/* Denominations
2018-02-08 06:46:44 +01:00
A note about convertibility . Within mixing pools , each denomination
is convertible to another .
2017-06-30 20:30:16 +02:00
For example :
1 DRK + 1000 = = ( .1 DRK + 100 ) * 10
10 DRK + 10000 = = ( 1 DRK + 1000 ) * 10
*/
/* Disabled
vecStandardDenominations . push_back ( ( 100 * COIN ) + 100000 ) ;
*/
2018-11-05 10:29:07 +01:00
vecStandardDenominations . push_back ( ( 10 * COIN ) + 10000 ) ;
vecStandardDenominations . push_back ( ( 1 * COIN ) + 1000 ) ;
vecStandardDenominations . push_back ( ( .1 * COIN ) + 100 ) ;
vecStandardDenominations . push_back ( ( .01 * COIN ) + 10 ) ;
2017-06-30 20:30:16 +02:00
/* Disabled till we need them
vecStandardDenominations . push_back ( ( .001 * COIN ) + 1 ) ;
*/
}
2017-05-05 13:26:27 +02:00
// check to make sure the collateral provided by the client is valid
bool CPrivateSend : : IsCollateralValid ( const CTransaction & txCollateral )
{
2018-11-05 10:29:07 +01:00
if ( txCollateral . vout . empty ( ) ) return false ;
if ( txCollateral . nLockTime ! = 0 ) return false ;
2017-05-05 13:26:27 +02:00
CAmount nValueIn = 0 ;
CAmount nValueOut = 0 ;
2018-02-06 12:09:33 +01:00
for ( const auto & txout : txCollateral . vout ) {
2017-05-05 13:26:27 +02:00
nValueOut + = txout . nValue ;
2018-03-15 10:22:22 +01:00
bool fAllowData = mnpayments . GetMinMasternodePaymentsProto ( ) > 70208 ;
2018-11-05 10:29:07 +01:00
if ( ! txout . scriptPubKey . IsPayToPublicKeyHash ( ) & & ! ( fAllowData & & txout . scriptPubKey . IsUnspendable ( ) ) ) {
LogPrintf ( " CPrivateSend::IsCollateralValid -- Invalid Script, txCollateral=%s " , txCollateral . ToString ( ) ) ;
2017-05-05 13:26:27 +02:00
return false ;
}
}
2018-02-06 12:09:33 +01:00
for ( const auto & txin : txCollateral . vin ) {
2017-09-26 16:33:46 +02:00
Coin coin ;
2018-11-05 10:29:07 +01:00
if ( ! GetUTXOCoin ( txin . prevout , coin ) ) {
2017-08-25 14:56:48 +02:00
LogPrint ( " privatesend " , " CPrivateSend::IsCollateralValid -- Unknown inputs in collateral transaction, txCollateral=%s " , txCollateral . ToString ( ) ) ;
return false ;
2017-05-05 13:26:27 +02:00
}
2017-09-26 16:33:46 +02:00
nValueIn + = coin . out . nValue ;
2017-05-05 13:26:27 +02:00
}
2017-06-30 20:30:16 +02:00
//collateral transactions are required to pay out a small fee to the miners
2018-11-05 10:29:07 +01:00
if ( nValueIn - nValueOut < GetCollateralAmount ( ) ) {
2017-05-05 13:26:27 +02:00
LogPrint ( " privatesend " , " CPrivateSend::IsCollateralValid -- did not include enough fees in transaction: fees: %d, txCollateral=%s " , nValueOut - nValueIn , txCollateral . ToString ( ) ) ;
return false ;
}
LogPrint ( " privatesend " , " CPrivateSend::IsCollateralValid -- %s " , txCollateral . ToString ( ) ) ;
{
LOCK ( cs_main ) ;
CValidationState validationState ;
2018-11-05 10:29:07 +01:00
if ( ! AcceptToMemoryPool ( mempool , validationState , MakeTransactionRef ( txCollateral ) , false , NULL , false , maxTxFee , true ) ) {
2017-05-05 13:26:27 +02:00
LogPrint ( " privatesend " , " CPrivateSend::IsCollateralValid -- didn't pass AcceptToMemoryPool() \n " ) ;
return false ;
}
}
return true ;
}
2017-12-04 07:06:07 +01:00
bool CPrivateSend : : IsCollateralAmount ( CAmount nInputAmount )
{
2018-03-15 10:22:22 +01:00
if ( mnpayments . GetMinMasternodePaymentsProto ( ) > 70208 ) {
2018-03-19 14:08:57 +01:00
// collateral input can be anything between 1x and "max" (including both)
return ( nInputAmount > = GetCollateralAmount ( ) & & nInputAmount < = GetMaxCollateralAmount ( ) ) ;
2018-03-15 10:22:22 +01:00
} else { // <= 70208
2018-03-19 14:08:57 +01:00
// collateral input can be anything between 2x and "max" (including both)
return ( nInputAmount > = GetCollateralAmount ( ) * 2 & & nInputAmount < = GetMaxCollateralAmount ( ) ) ;
2018-03-15 10:22:22 +01:00
}
2017-12-04 07:06:07 +01:00
}
2017-05-05 13:26:27 +02:00
/* Create a nice string to show the denominations
Function returns as follows ( for 4 denominations ) :
( bit on if present )
2018-02-08 06:46:44 +01:00
bit 0 - 10
bit 1 - 1
bit 2 - .1
bit 3 - .01
2017-05-05 13:26:27 +02:00
bit 4 and so on - out - of - bounds
none of above - non - denom
*/
std : : string CPrivateSend : : GetDenominationsToString ( int nDenom )
{
std : : string strDenom = " " ;
2017-06-30 20:30:16 +02:00
int nMaxDenoms = vecStandardDenominations . size ( ) ;
2017-05-05 13:26:27 +02:00
2018-11-05 10:29:07 +01:00
if ( nDenom > = ( 1 < < nMaxDenoms ) ) {
2017-05-05 13:26:27 +02:00
return " out-of-bounds " ;
}
for ( int i = 0 ; i < nMaxDenoms ; + + i ) {
2018-11-05 10:29:07 +01:00
if ( nDenom & ( 1 < < i ) ) {
2017-06-30 20:30:16 +02:00
strDenom + = ( strDenom . empty ( ) ? " " : " + " ) + FormatMoney ( vecStandardDenominations [ i ] ) ;
2017-05-05 13:26:27 +02:00
}
}
2018-11-05 10:29:07 +01:00
if ( strDenom . empty ( ) ) {
2017-05-05 13:26:27 +02:00
return " non-denom " ;
}
return strDenom ;
}
/* Return a bitshifted integer representing the denominations in this list
Function returns as follows ( for 4 denominations ) :
( bit on if present )
2018-02-08 06:46:44 +01:00
10 - bit 0
1 - bit 1
.1 - bit 2
.01 - bit 3
2017-05-05 13:26:27 +02:00
non - denom - 0 , all bits off
*/
int CPrivateSend : : GetDenominations ( const std : : vector < CTxOut > & vecTxOut , bool fSingleRandomDenom )
{
std : : vector < std : : pair < CAmount , int > > vecDenomUsed ;
// make a list of denominations, with zero uses
2018-02-06 12:09:33 +01:00
for ( const auto & nDenomValue : vecStandardDenominations )
2017-05-05 13:26:27 +02:00
vecDenomUsed . push_back ( std : : make_pair ( nDenomValue , 0 ) ) ;
// look for denominations and update uses to 1
2018-02-06 12:09:33 +01:00
for ( const auto & txout : vecTxOut ) {
2017-05-05 13:26:27 +02:00
bool found = false ;
2018-02-06 12:09:33 +01:00
for ( auto & s : vecDenomUsed ) {
2018-11-05 10:29:07 +01:00
if ( txout . nValue = = s . first ) {
2017-05-05 13:26:27 +02:00
s . second = 1 ;
found = true ;
}
}
2018-11-05 10:29:07 +01:00
if ( ! found ) return 0 ;
2017-05-05 13:26:27 +02:00
}
int nDenom = 0 ;
int c = 0 ;
// if the denomination is used, shift the bit on
2018-02-06 12:09:33 +01:00
for ( const auto & s : vecDenomUsed ) {
2017-05-05 13:26:27 +02:00
int bit = ( fSingleRandomDenom ? GetRandInt ( 2 ) : 1 ) & s . second ;
nDenom | = bit < < c + + ;
2018-11-05 10:29:07 +01:00
if ( fSingleRandomDenom & & bit ) break ; // use just one random denomination
2017-05-05 13:26:27 +02:00
}
return nDenom ;
}
2018-11-05 10:29:07 +01:00
bool CPrivateSend : : GetDenominationsBits ( int nDenom , std : : vector < int > & vecBitsRet )
2017-05-05 13:26:27 +02:00
{
// ( bit on if present, 4 denominations example )
// bit 0 - 100DASH+1
// bit 1 - 10DASH+1
// bit 2 - 1DASH+1
// bit 3 - .1DASH+1
2017-06-30 20:30:16 +02:00
int nMaxDenoms = vecStandardDenominations . size ( ) ;
2017-05-05 13:26:27 +02:00
2018-11-05 10:29:07 +01:00
if ( nDenom > = ( 1 < < nMaxDenoms ) ) return false ;
2017-05-05 13:26:27 +02:00
vecBitsRet . clear ( ) ;
for ( int i = 0 ; i < nMaxDenoms ; + + i ) {
2018-11-05 10:29:07 +01:00
if ( nDenom & ( 1 < < i ) ) {
2017-05-05 13:26:27 +02:00
vecBitsRet . push_back ( i ) ;
}
}
return ! vecBitsRet . empty ( ) ;
}
int CPrivateSend : : GetDenominationsByAmounts ( const std : : vector < CAmount > & vecAmount )
{
CScript scriptTmp = CScript ( ) ;
std : : vector < CTxOut > vecTxOut ;
2018-07-12 11:07:51 +02:00
for ( auto it = vecAmount . rbegin ( ) ; it ! = vecAmount . rend ( ) ; + + it ) {
CTxOut txout ( ( * it ) , scriptTmp ) ;
2017-05-05 13:26:27 +02:00
vecTxOut . push_back ( txout ) ;
}
return GetDenominations ( vecTxOut , true ) ;
}
2017-12-04 07:06:07 +01:00
bool CPrivateSend : : IsDenominatedAmount ( CAmount nInputAmount )
{
for ( const auto & nDenomValue : vecStandardDenominations )
2018-11-05 10:29:07 +01:00
if ( nInputAmount = = nDenomValue )
2017-12-04 07:06:07 +01:00
return true ;
return false ;
}
2017-05-05 13:26:27 +02:00
std : : string CPrivateSend : : GetMessageByID ( PoolMessage nMessageID )
{
switch ( nMessageID ) {
2018-11-05 10:29:07 +01:00
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 _ ( " Entry exceeds maximum size. " ) ;
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. " ) ; // not used
case ERR_QUEUE_FULL :
return _ ( " Masternode queue is full. " ) ;
case ERR_RECENT :
return _ ( " Last PrivateSend 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_NOERR :
return _ ( " No errors detected. " ) ;
case MSG_SUCCESS :
return _ ( " Transaction created successfully. " ) ;
case MSG_ENTRIES_ADDED :
return _ ( " Your entries added successfully. " ) ;
default :
return _ ( " Unknown response. " ) ;
2017-05-05 13:26:27 +02:00
}
}
2018-10-25 16:31:32 +02:00
void CPrivateSend : : AddDSTX ( const CPrivateSendBroadcastTx & dstx )
2017-05-05 13:26:27 +02:00
{
2017-06-30 20:30:16 +02:00
LOCK ( cs_mapdstx ) ;
2017-09-20 14:02:53 +02:00
mapDSTX . insert ( std : : make_pair ( dstx . tx - > GetHash ( ) , dstx ) ) ;
2017-05-05 13:26:27 +02:00
}
2018-10-25 16:31:32 +02:00
CPrivateSendBroadcastTx CPrivateSend : : GetDSTX ( const uint256 & hash )
2017-05-05 13:26:27 +02:00
{
2017-06-30 20:30:16 +02:00
LOCK ( cs_mapdstx ) ;
auto it = mapDSTX . find ( hash ) ;
2018-10-25 16:31:32 +02:00
return ( it = = mapDSTX . end ( ) ) ? CPrivateSendBroadcastTx ( ) : it - > second ;
2017-05-05 13:26:27 +02:00
}
2017-07-10 16:42:09 +02:00
void CPrivateSend : : CheckDSTXes ( int nHeight )
{
LOCK ( cs_mapdstx ) ;
2018-10-25 16:31:32 +02:00
std : : map < uint256 , CPrivateSendBroadcastTx > : : iterator it = mapDSTX . begin ( ) ;
2018-11-05 10:29:07 +01:00
while ( it ! = mapDSTX . end ( ) ) {
2017-07-10 16:42:09 +02:00
if ( it - > second . IsExpired ( nHeight ) ) {
mapDSTX . erase ( it + + ) ;
} else {
+ + it ;
}
}
LogPrint ( " privatesend " , " CPrivateSend::CheckDSTXes -- mapDSTX.size()=%llu \n " , mapDSTX . size ( ) ) ;
}
2018-11-05 10:29:07 +01:00
void CPrivateSend : : UpdatedBlockTip ( const CBlockIndex * pindex )
2017-12-07 10:42:47 +01:00
{
2018-11-05 10:29:07 +01:00
if ( pindex & & ! fLiteMode & & masternodeSync . IsMasternodeListSynced ( ) ) {
2017-12-07 10:42:47 +01:00
CheckDSTXes ( pindex - > nHeight ) ;
}
}
2018-11-05 10:29:07 +01:00
void CPrivateSend : : SyncTransaction ( const CTransaction & tx , const CBlockIndex * pindex , int posInBlock )
2017-07-10 16:42:09 +02:00
{
if ( tx . IsCoinBase ( ) ) return ;
LOCK2 ( cs_main , cs_mapdstx ) ;
uint256 txHash = tx . GetHash ( ) ;
if ( ! mapDSTX . count ( txHash ) ) return ;
2018-01-08 18:41:06 +01:00
// When tx is 0-confirmed or conflicted, posInBlock is SYNC_TRANSACTION_NOT_IN_BLOCK and nConfirmedHeight should be set to -1
mapDSTX [ txHash ] . SetConfirmedHeight ( posInBlock = = CMainSignals : : SYNC_TRANSACTION_NOT_IN_BLOCK ? - 1 : pindex - > nHeight ) ;
2018-09-04 12:54:59 +02:00
LogPrint ( " privatesend " , " CPrivateSend::SyncTransaction -- txid=%s \n " , txHash . ToString ( ) ) ;
2017-07-10 16:42:09 +02:00
}