2014-12-09 02:17:57 +01:00
# include "sync.h"
# include "net.h"
# include "key.h"
# include "util.h"
# include "base58.h"
# include "protocol.h"
# include "instantx.h"
# include "activemasternode.h"
2015-02-23 21:01:21 +01:00
# include "masternodeman.h"
2014-12-09 02:17:57 +01:00
# include "darksend.h"
2015-02-09 20:28:29 +01:00
# include "spork.h"
2014-12-09 02:17:57 +01:00
# include <boost/lexical_cast.hpp>
using namespace std ;
using namespace boost ;
2014-12-31 03:54:00 +01:00
2014-12-09 02:17:57 +01:00
std : : map < uint256 , CTransaction > mapTxLockReq ;
std : : map < uint256 , CTransaction > mapTxLockReqRejected ;
2015-02-06 20:07:22 +01:00
std : : map < uint256 , CConsensusVote > mapTxLockVote ;
2014-12-09 02:17:57 +01:00
std : : map < uint256 , CTransactionLock > mapTxLocks ;
2015-02-04 21:20:13 +01:00
std : : map < COutPoint , uint256 > mapLockedInputs ;
2015-02-02 18:33:52 +01:00
std : : map < uint256 , int64_t > mapUnknownVotes ; //track votes with no tx for DOS
2015-02-01 21:04:20 +01:00
int nCompleteTXLocks ;
2014-12-09 02:17:57 +01:00
//txlock - Locks transaction
//
//step 1.) Broadcast intention to lock transaction inputs, "txlreg", CTransaction
2015-06-04 20:54:33 +02:00
//step 2.) Top INSTANTX_SIGNATURES_TOTAL masternodes, open connect to top 1 masternode.
// Send "txvote", CTransaction, Signature, Approve
//step 3.) Top 1 masternode, waits for INSTANTX_SIGNATURES_REQUIRED messages. Upon success, sends "txlock'
2014-12-09 02:17:57 +01:00
void ProcessMessageInstantX ( CNode * pfrom , std : : string & strCommand , CDataStream & vRecv )
{
2015-01-18 16:28:16 +01:00
if ( fLiteMode ) return ; //disable all darksend/masternode related functionality
2015-02-09 20:28:29 +01:00
if ( ! IsSporkActive ( SPORK_2_INSTANTX ) ) return ;
2015-02-26 15:40:43 +01:00
if ( IsInitialBlockDownload ( ) ) return ;
2014-12-09 02:17:57 +01:00
2015-07-10 00:08:26 +02:00
if ( strCommand = = " ix " )
2014-12-09 02:17:57 +01:00
{
2015-07-10 00:08:26 +02:00
//LogPrintf("ProcessMessageInstantX::ix\n");
2014-12-09 02:17:57 +01:00
CDataStream vMsg ( vRecv ) ;
CTransaction tx ;
vRecv > > tx ;
CInv inv ( MSG_TXLOCK_REQUEST , tx . GetHash ( ) ) ;
pfrom - > AddInventoryKnown ( inv ) ;
2015-02-02 15:36:00 +01:00
if ( mapTxLockReq . count ( tx . GetHash ( ) ) | | mapTxLockReqRejected . count ( tx . GetHash ( ) ) ) {
2014-12-09 02:17:57 +01:00
return ;
}
2015-02-04 11:44:41 +01:00
if ( ! IsIXTXValid ( tx ) ) {
return ;
}
2014-12-09 02:17:57 +01:00
BOOST_FOREACH ( const CTxOut o , tx . vout ) {
2015-07-12 23:02:39 +02:00
// IX supports normal scripts and unspendable scripts (used in DS collateral and Budget collateral).
// TODO: Look into other script types that are normal and can be included
if ( ! o . scriptPubKey . IsNormalPaymentScript ( ) & & ! o . scriptPubKey . IsUnspendable ( ) ) {
2015-07-10 00:08:26 +02:00
LogPrintf ( " ProcessMessageInstantX::ix - Invalid Script %s \n " , tx . ToString ( ) . c_str ( ) ) ;
2014-12-09 02:17:57 +01:00
return ;
}
}
2015-02-04 22:59:19 +01:00
int nBlockHeight = CreateNewLock ( tx ) ;
2014-12-09 02:17:57 +01:00
bool fMissingInputs = false ;
CValidationState state ;
2014-12-31 03:54:00 +01:00
2015-07-30 15:44:18 +02:00
LOCK ( cs_main ) ;
2014-12-09 02:17:57 +01:00
if ( AcceptToMemoryPool ( mempool , state , tx , true , & fMissingInputs ) )
{
2015-02-06 20:07:22 +01:00
vector < CInv > vInv ;
vInv . push_back ( inv ) ;
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
pnode - > PushMessage ( " inv " , vInv ) ;
2015-02-04 22:59:19 +01:00
DoConsensusVote ( tx , nBlockHeight ) ;
2014-12-09 02:17:57 +01:00
2015-02-02 15:36:00 +01:00
mapTxLockReq . insert ( make_pair ( tx . GetHash ( ) , tx ) ) ;
2014-12-09 02:17:57 +01:00
2015-07-10 00:08:26 +02:00
LogPrintf ( " ProcessMessageInstantX::ix - Transaction Lock Request: %s %s : accepted %s \n " ,
2014-12-09 02:17:57 +01:00
pfrom - > addr . ToString ( ) . c_str ( ) , pfrom - > cleanSubVer . c_str ( ) ,
tx . GetHash ( ) . ToString ( ) . c_str ( )
) ;
return ;
} else {
2015-02-03 18:17:30 +01:00
mapTxLockReqRejected . insert ( make_pair ( tx . GetHash ( ) , tx ) ) ;
2014-12-09 02:17:57 +01:00
// can we get the conflicting transaction as proof?
2015-07-10 00:08:26 +02:00
LogPrintf ( " ProcessMessageInstantX::ix - Transaction Lock Request: %s %s : rejected %s \n " ,
2014-12-09 02:17:57 +01:00
pfrom - > addr . ToString ( ) . c_str ( ) , pfrom - > cleanSubVer . c_str ( ) ,
tx . GetHash ( ) . ToString ( ) . c_str ( )
) ;
2015-02-04 21:20:13 +01:00
BOOST_FOREACH ( const CTxIn & in , tx . vin ) {
if ( ! mapLockedInputs . count ( in . prevout ) ) {
mapLockedInputs . insert ( make_pair ( in . prevout , tx . GetHash ( ) ) ) ;
}
}
2015-02-03 18:17:30 +01:00
// resolve conflicts
2015-02-03 23:40:00 +01:00
std : : map < uint256 , CTransactionLock > : : iterator i = mapTxLocks . find ( tx . GetHash ( ) ) ;
2015-02-03 18:17:30 +01:00
if ( i ! = mapTxLocks . end ( ) ) {
2015-02-04 02:19:54 +01:00
//we only care if we have a complete tx lock
2015-02-03 18:17:30 +01:00
if ( ( * i ) . second . CountSignatures ( ) > = INSTANTX_SIGNATURES_REQUIRED ) {
2015-02-05 17:48:57 +01:00
if ( ! CheckForConflictingLocks ( tx ) ) {
2015-07-10 00:08:26 +02:00
LogPrintf ( " ProcessMessageInstantX::ix - Found Existing Complete IX Lock \n " ) ;
2015-02-03 18:17:30 +01:00
2015-07-31 20:53:40 +02:00
//reprocess the last 15 blocks
2015-08-03 01:08:37 +02:00
ReprocessBlocks ( 15 ) ;
2015-02-05 17:48:57 +01:00
mapTxLockReq . insert ( make_pair ( tx . GetHash ( ) , tx ) ) ;
}
2015-02-03 18:17:30 +01:00
}
2015-02-03 23:40:00 +01:00
}
2015-02-03 18:17:30 +01:00
2014-12-09 02:17:57 +01:00
return ;
}
2014-12-31 03:54:00 +01:00
}
2014-12-09 02:17:57 +01:00
else if ( strCommand = = " txlvote " ) //InstantX Lock Consensus Votes
{
CConsensusVote ctx ;
vRecv > > ctx ;
2015-02-01 16:53:49 +01:00
CInv inv ( MSG_TXLOCK_VOTE , ctx . GetHash ( ) ) ;
2014-12-09 02:17:57 +01:00
pfrom - > AddInventoryKnown ( inv ) ;
2015-02-01 21:37:20 +01:00
if ( mapTxLockVote . count ( ctx . GetHash ( ) ) ) {
2015-02-01 16:53:49 +01:00
return ;
}
2014-12-09 02:17:57 +01:00
2015-02-06 20:07:22 +01:00
mapTxLockVote . insert ( make_pair ( ctx . GetHash ( ) , ctx ) ) ;
2014-12-31 03:54:00 +01:00
2015-02-02 15:36:00 +01:00
if ( ProcessConsensusVote ( ctx ) ) {
//Spam/Dos protection
2015-02-02 18:33:52 +01:00
/*
Masternodes will sometimes propagate votes before the transaction is known to the client .
This tracks those messages and allows it at the same rate of the rest of the network , if
a peer violates it , it will simply be ignored
*/
2015-02-02 15:36:00 +01:00
if ( ! mapTxLockReq . count ( ctx . txHash ) & & ! mapTxLockReqRejected . count ( ctx . txHash ) ) {
if ( ! mapUnknownVotes . count ( ctx . vinMasternode . prevout . hash ) ) {
mapUnknownVotes [ ctx . vinMasternode . prevout . hash ] = GetTime ( ) + ( 60 * 10 ) ;
}
2015-02-02 18:33:52 +01:00
if ( mapUnknownVotes [ ctx . vinMasternode . prevout . hash ] > GetTime ( ) & &
mapUnknownVotes [ ctx . vinMasternode . prevout . hash ] - GetAverageVoteTime ( ) > 60 * 10 ) {
2015-07-10 00:08:26 +02:00
LogPrintf ( " ProcessMessageInstantX::ix - masternode is spamming transaction votes: %s %s \n " ,
2015-02-02 18:33:52 +01:00
ctx . vinMasternode . ToString ( ) . c_str ( ) ,
ctx . txHash . ToString ( ) . c_str ( )
) ;
return ;
2015-02-02 15:36:00 +01:00
} else {
mapUnknownVotes [ ctx . vinMasternode . prevout . hash ] = GetTime ( ) + ( 60 * 10 ) ;
}
}
2015-02-06 20:07:22 +01:00
vector < CInv > vInv ;
vInv . push_back ( inv ) ;
2015-02-02 15:36:00 +01:00
LOCK ( cs_vNodes ) ;
BOOST_FOREACH ( CNode * pnode , vNodes )
2015-02-06 20:07:22 +01:00
pnode - > PushMessage ( " inv " , vInv ) ;
2015-02-02 13:01:06 +01:00
2014-12-09 02:17:57 +01:00
}
2015-02-01 21:37:20 +01:00
2015-02-01 16:53:49 +01:00
return ;
2014-12-09 02:17:57 +01:00
}
}
2015-02-04 11:44:41 +01:00
bool IsIXTXValid ( const CTransaction & txCollateral ) {
if ( txCollateral . vout . size ( ) < 1 ) return false ;
if ( txCollateral . nLockTime ! = 0 ) return false ;
int64_t nValueIn = 0 ;
int64_t nValueOut = 0 ;
bool missingTx = false ;
BOOST_FOREACH ( const CTxOut o , txCollateral . vout )
nValueOut + = o . nValue ;
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 ) {
nValueIn + = tx2 . vout [ i . prevout . n ] . nValue ;
}
} else {
missingTx = true ;
}
}
2015-02-11 15:47:21 +01:00
if ( nValueOut > GetSporkValue ( SPORK_5_MAX_VALUE ) * COIN ) {
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " IsIXTXValid - Transaction value too high - %s \n " , txCollateral . ToString ( ) . c_str ( ) ) ;
2015-02-11 15:47:21 +01:00
return false ;
}
2015-02-04 11:44:41 +01:00
if ( missingTx ) {
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " IsIXTXValid - Unknown inputs in IX transaction - %s \n " , txCollateral . ToString ( ) . c_str ( ) ) ;
2015-02-08 04:04:08 +01:00
/*
This happens sometimes for an unknown reason , so we ' ll return that it ' s a valid transaction .
If someone submits an invalid transaction it will be rejected by the network anyway and this isn ' t
very common , but we don ' t want to block IX just because the client can ' t figure out the fee .
*/
return true ;
2015-02-04 11:44:41 +01:00
}
if ( nValueIn - nValueOut < COIN * 0.01 ) {
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " IsIXTXValid - did not include enough fees in transaction %d \n %s \n " , nValueOut - nValueIn , txCollateral . ToString ( ) . c_str ( ) ) ;
2015-02-04 11:44:41 +01:00
return false ;
}
return true ;
}
2015-02-04 22:59:19 +01:00
int64_t CreateNewLock ( CTransaction tx )
2014-12-09 02:17:57 +01:00
{
2015-02-04 22:59:19 +01:00
int64_t nTxAge = 0 ;
BOOST_REVERSE_FOREACH ( CTxIn i , tx . vin ) {
nTxAge = GetInputAge ( i ) ;
2015-08-04 19:42:05 +02:00
if ( nTxAge < 5 ) //1 less than the "send IX" gui requires, incase of a block propagating the network at the time
2015-02-04 22:59:19 +01:00
{
2015-02-05 05:05:36 +01:00
LogPrintf ( " CreateNewLock - Transaction not found / too new: %d / %s \n " , nTxAge , tx . GetHash ( ) . ToString ( ) . c_str ( ) ) ;
2015-02-04 22:59:19 +01:00
return 0 ;
}
}
2014-12-09 02:17:57 +01:00
2015-02-04 22:09:50 +01:00
/*
2015-02-04 22:59:19 +01:00
Use a blockheight newer than the input .
This prevents attackers from using transaction mallibility to predict which masternodes
they ' ll use .
2015-02-04 22:09:50 +01:00
*/
2015-02-04 22:59:19 +01:00
int nBlockHeight = ( chainActive . Tip ( ) - > nHeight - nTxAge ) + 4 ;
2015-02-04 22:09:50 +01:00
if ( ! mapTxLocks . count ( tx . GetHash ( ) ) ) {
2015-02-05 05:05:36 +01:00
LogPrintf ( " CreateNewLock - New Transaction Lock %s ! \n " , tx . GetHash ( ) . ToString ( ) . c_str ( ) ) ;
2015-02-04 22:09:50 +01:00
CTransactionLock newLock ;
newLock . nBlockHeight = nBlockHeight ;
2015-07-07 14:47:22 +02:00
newLock . nExpiration = GetTime ( ) + ( 60 * 60 ) ; //locks expire after 60 minutes (24 confirmations)
2015-02-05 16:52:02 +01:00
newLock . nTimeout = GetTime ( ) + ( 60 * 5 ) ;
2015-02-04 22:09:50 +01:00
newLock . txHash = tx . GetHash ( ) ;
mapTxLocks . insert ( make_pair ( tx . GetHash ( ) , newLock ) ) ;
} else {
mapTxLocks [ tx . GetHash ( ) ] . nBlockHeight = nBlockHeight ;
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " CreateNewLock - Transaction Lock Exists %s ! \n " , tx . GetHash ( ) . ToString ( ) . c_str ( ) ) ;
2015-02-04 22:09:50 +01:00
}
2015-03-13 10:28:20 +01:00
2015-02-04 22:59:19 +01:00
return nBlockHeight ;
}
// check if we need to vote on this transaction
void DoConsensusVote ( CTransaction & tx , int64_t nBlockHeight )
{
if ( ! fMasterNode ) return ;
2015-02-23 21:01:21 +01:00
int n = mnodeman . GetMasternodeRank ( activeMasternode . vin , nBlockHeight , MIN_INSTANTX_PROTO_VERSION ) ;
2015-02-06 05:41:17 +01:00
if ( n = = - 1 )
{
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " InstantX::DoConsensusVote - Unknown Masternode \n " ) ;
2015-02-06 05:41:17 +01:00
return ;
}
if ( n > INSTANTX_SIGNATURES_TOTAL )
{
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " InstantX::DoConsensusVote - Masternode not in the top %d (%d) \n " , INSTANTX_SIGNATURES_TOTAL , n ) ;
2015-02-06 05:41:17 +01:00
return ;
}
2015-02-04 22:59:19 +01:00
/*
nBlockHeight calculated from the transaction is the authoritive source
*/
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " InstantX::DoConsensusVote - In the top %d (%d) \n " , INSTANTX_SIGNATURES_TOTAL , n ) ;
2015-02-06 05:41:17 +01:00
2014-12-09 02:17:57 +01:00
CConsensusVote ctx ;
2014-12-06 20:41:53 +01:00
ctx . vinMasternode = activeMasternode . vin ;
2015-02-02 13:24:04 +01:00
ctx . txHash = tx . GetHash ( ) ;
2014-12-31 03:54:00 +01:00
ctx . nBlockHeight = nBlockHeight ;
2014-12-09 02:17:57 +01:00
if ( ! ctx . Sign ( ) ) {
LogPrintf ( " InstantX::DoConsensusVote - Failed to sign consensus vote \n " ) ;
return ;
}
if ( ! ctx . SignatureValid ( ) ) {
LogPrintf ( " InstantX::DoConsensusVote - Signature invalid \n " ) ;
return ;
}
2015-02-02 13:01:06 +01:00
2015-02-06 20:07:22 +01:00
mapTxLockVote [ ctx . GetHash ( ) ] = ctx ;
CInv inv ( MSG_TXLOCK_VOTE , ctx . GetHash ( ) ) ;
2015-07-08 02:37:23 +02:00
RelayInv ( inv ) ;
2014-12-09 02:17:57 +01:00
}
//received a consensus vote
2015-02-02 15:36:00 +01:00
bool ProcessConsensusVote ( CConsensusVote & ctx )
2014-12-09 02:17:57 +01:00
{
2015-02-23 21:01:21 +01:00
int n = mnodeman . GetMasternodeRank ( ctx . vinMasternode , ctx . nBlockHeight , MIN_INSTANTX_PROTO_VERSION ) ;
2014-12-09 02:17:57 +01:00
2015-02-25 12:54:03 +01:00
CMasternode * pmn = mnodeman . Find ( ctx . vinMasternode ) ;
if ( pmn ! = NULL )
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " InstantX::ProcessConsensusVote - Masternode ADDR %s %d \n " , pmn - > addr . ToString ( ) . c_str ( ) , n ) ;
2015-02-06 16:54:39 +01:00
2014-12-31 03:54:00 +01:00
if ( n = = - 1 )
2014-12-09 02:17:57 +01:00
{
2015-02-06 17:03:50 +01:00
//can be caused by past versions trying to vote with an invalid protocol
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " InstantX::ProcessConsensusVote - Unknown Masternode \n " ) ;
2015-02-02 15:36:00 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
2015-02-05 18:56:11 +01:00
if ( n > INSTANTX_SIGNATURES_TOTAL )
2014-12-09 02:17:57 +01:00
{
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " InstantX::ProcessConsensusVote - Masternode not in the top %d (%d) - %s \n " , INSTANTX_SIGNATURES_TOTAL , n , ctx . GetHash ( ) . ToString ( ) . c_str ( ) ) ;
2015-02-02 15:36:00 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
if ( ! ctx . SignatureValid ( ) ) {
LogPrintf ( " InstantX::ProcessConsensusVote - Signature invalid \n " ) ;
//don't ban, it could just be a non-synced masternode
2015-02-02 15:36:00 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
2015-02-02 13:24:04 +01:00
if ( ! mapTxLocks . count ( ctx . txHash ) ) {
LogPrintf ( " InstantX::ProcessConsensusVote - New Transaction Lock %s ! \n " , ctx . txHash . ToString ( ) . c_str ( ) ) ;
2015-02-01 21:04:20 +01:00
2015-02-01 16:53:49 +01:00
CTransactionLock newLock ;
2015-02-04 22:09:50 +01:00
newLock . nBlockHeight = 0 ;
2015-02-01 21:04:20 +01:00
newLock . nExpiration = GetTime ( ) + ( 60 * 60 ) ;
2015-02-05 16:52:02 +01:00
newLock . nTimeout = GetTime ( ) + ( 60 * 5 ) ;
2015-02-02 13:24:04 +01:00
newLock . txHash = ctx . txHash ;
mapTxLocks . insert ( make_pair ( ctx . txHash , newLock ) ) ;
2015-06-24 23:11:45 +02:00
} else
LogPrint ( " instantx " , " InstantX::ProcessConsensusVote - Transaction Lock Exists %s ! \n " , ctx . txHash . ToString ( ) . c_str ( ) ) ;
2015-02-01 16:53:49 +01:00
2014-12-09 02:17:57 +01:00
//compile consessus vote
2015-02-02 13:24:04 +01:00
std : : map < uint256 , CTransactionLock > : : iterator i = mapTxLocks . find ( ctx . txHash ) ;
2015-02-01 16:53:49 +01:00
if ( i ! = mapTxLocks . end ( ) ) {
( * i ) . second . AddSignature ( ctx ) ;
2015-02-03 23:40:00 +01:00
2015-02-05 19:29:13 +01:00
# ifdef ENABLE_WALLET
if ( pwalletMain ) {
//when we get back signatures, we'll count them as requests. Otherwise the client will think it didn't propagate.
if ( pwalletMain - > mapRequestCount . count ( ctx . txHash ) )
pwalletMain - > mapRequestCount [ ctx . txHash ] + + ;
}
# endif
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " InstantX::ProcessConsensusVote - Transaction Lock Votes %d - %s ! \n " , ( * i ) . second . CountSignatures ( ) , ctx . GetHash ( ) . ToString ( ) . c_str ( ) ) ;
2015-02-03 23:40:00 +01:00
2015-02-01 16:53:49 +01:00
if ( ( * i ) . second . CountSignatures ( ) > = INSTANTX_SIGNATURES_REQUIRED ) {
2015-06-24 23:11:45 +02:00
LogPrint ( " instantx " , " InstantX::ProcessConsensusVote - Transaction Lock Is Complete %s ! \n " , ( * i ) . second . GetHash ( ) . ToString ( ) . c_str ( ) ) ;
2015-02-03 18:17:30 +01:00
2015-02-05 17:48:57 +01:00
CTransaction & tx = mapTxLockReq [ ctx . txHash ] ;
if ( ! CheckForConflictingLocks ( tx ) ) {
2015-02-04 22:19:18 +01:00
# ifdef ENABLE_WALLET
2015-02-05 17:48:57 +01:00
if ( pwalletMain ) {
if ( pwalletMain - > UpdatedTransaction ( ( * i ) . second . txHash ) ) {
nCompleteTXLocks + + ;
}
2015-02-04 22:19:18 +01:00
}
# endif
2015-02-03 18:17:30 +01:00
2015-02-05 17:48:57 +01:00
if ( mapTxLockReq . count ( ctx . txHash ) ) {
BOOST_FOREACH ( const CTxIn & in , tx . vin ) {
if ( ! mapLockedInputs . count ( in . prevout ) ) {
mapLockedInputs . insert ( make_pair ( in . prevout , ctx . txHash ) ) ;
}
2015-02-04 21:20:13 +01:00
}
}
2015-02-05 17:48:57 +01:00
// resolve conflicts
2015-02-04 02:19:54 +01:00
2015-02-05 17:48:57 +01:00
//if this tx lock was rejected, we need to remove the conflicting blocks
if ( mapTxLockReqRejected . count ( ( * i ) . second . txHash ) ) {
2015-07-31 20:53:40 +02:00
//reprocess the last 15 blocks
2015-08-03 01:08:37 +02:00
ReprocessBlocks ( 15 ) ;
2015-02-05 17:48:57 +01:00
}
2015-02-03 23:40:00 +01:00
}
2014-12-09 02:17:57 +01:00
}
2015-02-02 15:36:00 +01:00
return true ;
2014-12-09 02:17:57 +01:00
}
2015-02-01 16:53:49 +01:00
2015-02-02 15:36:00 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
2015-02-05 17:48:57 +01:00
bool CheckForConflictingLocks ( CTransaction & tx )
{
/*
It ' s possible ( very unlikely though ) to get 2 conflicting transaction locks approved by the network .
In that case , they will cancel each other out .
Blocks could have been rejected during this time , which is OK . After they cancel out , the client will
rescan the blocks and find they ' re acceptable and then take the chain with the most work .
*/
BOOST_FOREACH ( const CTxIn & in , tx . vin ) {
if ( mapLockedInputs . count ( in . prevout ) ) {
if ( mapLockedInputs [ in . prevout ] ! = tx . GetHash ( ) ) {
LogPrintf ( " InstantX::CheckForConflictingLocks - found two complete conflicting locks - removing both. %s %s " , tx . GetHash ( ) . ToString ( ) . c_str ( ) , mapLockedInputs [ in . prevout ] . ToString ( ) . c_str ( ) ) ;
if ( mapTxLocks . count ( tx . GetHash ( ) ) ) mapTxLocks [ tx . GetHash ( ) ] . nExpiration = GetTime ( ) ;
if ( mapTxLocks . count ( mapLockedInputs [ in . prevout ] ) ) mapTxLocks [ mapLockedInputs [ in . prevout ] ] . nExpiration = GetTime ( ) ;
return true ;
}
}
}
return false ;
}
2015-02-02 18:33:52 +01:00
int64_t GetAverageVoteTime ( )
{
std : : map < uint256 , int64_t > : : iterator it = mapUnknownVotes . begin ( ) ;
int64_t total = 0 ;
int64_t count = 0 ;
while ( it ! = mapUnknownVotes . end ( ) ) {
total + = it - > second ;
count + + ;
it + + ;
}
return total / count ;
}
2014-12-09 02:17:57 +01:00
void CleanTransactionLocksList ( )
{
if ( chainActive . Tip ( ) = = NULL ) return ;
std : : map < uint256 , CTransactionLock > : : iterator it = mapTxLocks . begin ( ) ;
2014-12-31 03:54:00 +01:00
2014-12-09 02:17:57 +01:00
while ( it ! = mapTxLocks . end ( ) ) {
2015-02-01 21:04:20 +01:00
if ( GetTime ( ) > it - > second . nExpiration ) { //keep them for an hour
2015-02-02 13:24:04 +01:00
LogPrintf ( " Removing old transaction lock %s \n " , it - > second . txHash . ToString ( ) . c_str ( ) ) ;
2015-02-04 21:20:13 +01:00
2015-03-13 10:28:20 +01:00
// loop through masternodes that responded
for ( int nRank = 0 ; nRank < = INSTANTX_SIGNATURES_TOTAL ; nRank + + )
{
CMasternode * pmn = mnodeman . GetMasternodeByRank ( nRank , it - > second . nBlockHeight , MIN_INSTANTX_PROTO_VERSION ) ;
if ( ! pmn ) continue ;
bool fFound = false ;
BOOST_FOREACH ( CConsensusVote & v , it - > second . vecConsensusVotes )
{
if ( pmn - > vin = = v . vinMasternode ) { //Masternode responded
fFound = true ;
}
}
}
2015-02-04 21:20:13 +01:00
if ( mapTxLockReq . count ( it - > second . txHash ) ) {
CTransaction & tx = mapTxLockReq [ it - > second . txHash ] ;
2015-02-04 21:25:12 +01:00
2015-02-04 21:20:13 +01:00
BOOST_FOREACH ( const CTxIn & in , tx . vin )
mapLockedInputs . erase ( in . prevout ) ;
mapTxLockReq . erase ( it - > second . txHash ) ;
mapTxLockReqRejected . erase ( it - > second . txHash ) ;
2015-02-06 20:58:03 +01:00
BOOST_FOREACH ( CConsensusVote & v , it - > second . vecConsensusVotes )
mapTxLockVote . erase ( v . GetHash ( ) ) ;
2015-02-04 21:20:13 +01:00
}
2014-12-09 02:17:57 +01:00
mapTxLocks . erase ( it + + ) ;
} else {
it + + ;
}
}
}
2015-02-01 16:53:49 +01:00
uint256 CConsensusVote : : GetHash ( ) const
{
2015-02-08 04:54:36 +01:00
return vinMasternode . prevout . hash + vinMasternode . prevout . n + txHash ;
2015-02-01 16:53:49 +01:00
}
2014-12-09 02:17:57 +01:00
bool CConsensusVote : : SignatureValid ( )
{
std : : string errorMessage ;
2015-02-02 15:36:00 +01:00
std : : string strMessage = txHash . ToString ( ) . c_str ( ) + boost : : lexical_cast < std : : string > ( nBlockHeight ) ;
2015-02-01 16:53:49 +01:00
//LogPrintf("verify strMessage %s \n", strMessage.c_str());
2014-12-31 03:54:00 +01:00
2015-02-25 12:54:03 +01:00
CMasternode * pmn = mnodeman . Find ( vinMasternode ) ;
2014-12-09 02:17:57 +01:00
2015-02-25 12:54:03 +01:00
if ( pmn = = NULL )
2014-12-09 02:17:57 +01:00
{
LogPrintf ( " InstantX::CConsensusVote::SignatureValid() - Unknown Masternode \n " ) ;
return false ;
}
2015-02-01 16:53:49 +01:00
//LogPrintf("verify addr %s \n", vecMasternodes[0].addr.ToString().c_str());
//LogPrintf("verify addr %s \n", vecMasternodes[1].addr.ToString().c_str());
//LogPrintf("verify addr %d %s \n", n, vecMasternodes[n].addr.ToString().c_str());
2014-12-09 02:17:57 +01:00
CScript pubkey ;
2015-04-03 00:51:08 +02:00
pubkey = GetScriptForDestination ( pmn - > pubkey2 . GetID ( ) ) ;
2014-12-09 02:17:57 +01:00
CTxDestination address1 ;
ExtractDestination ( pubkey , address1 ) ;
CBitcoinAddress address2 ( address1 ) ;
2015-02-01 16:53:49 +01:00
//LogPrintf("verify pubkey2 %s \n", address2.ToString().c_str());
2014-12-09 02:17:57 +01:00
2015-02-25 12:54:03 +01:00
if ( ! darkSendSigner . VerifyMessage ( pmn - > pubkey2 , vchMasterNodeSignature , strMessage , errorMessage ) ) {
2014-12-09 02:17:57 +01:00
LogPrintf ( " InstantX::CConsensusVote::SignatureValid() - Verify message failed \n " ) ;
return false ;
}
return true ;
}
bool CConsensusVote : : Sign ( )
{
std : : string errorMessage ;
CKey key2 ;
CPubKey pubkey2 ;
2015-02-02 15:36:00 +01:00
std : : string strMessage = txHash . ToString ( ) . c_str ( ) + boost : : lexical_cast < std : : string > ( nBlockHeight ) ;
2015-02-01 16:53:49 +01:00
//LogPrintf("signing strMessage %s \n", strMessage.c_str());
//LogPrintf("signing privkey %s \n", strMasterNodePrivKey.c_str());
2014-12-09 02:17:57 +01:00
if ( ! darkSendSigner . SetKey ( strMasterNodePrivKey , errorMessage , key2 , pubkey2 ) )
{
2015-06-24 23:27:56 +02:00
LogPrintf ( " CConsensusVote::Sign() - ERROR: Invalid masternodeprivkey: '%s' \n " , errorMessage . c_str ( ) ) ;
2015-01-18 16:28:16 +01:00
return false ;
2014-12-09 02:17:57 +01:00
}
CScript pubkey ;
2015-04-03 00:51:08 +02:00
pubkey = GetScriptForDestination ( pubkey2 . GetID ( ) ) ;
2014-12-09 02:17:57 +01:00
CTxDestination address1 ;
ExtractDestination ( pubkey , address1 ) ;
CBitcoinAddress address2 ( address1 ) ;
2015-02-01 16:53:49 +01:00
//LogPrintf("signing pubkey2 %s \n", address2.ToString().c_str());
2014-12-09 02:17:57 +01:00
if ( ! darkSendSigner . SignMessage ( strMessage , errorMessage , vchMasterNodeSignature , key2 ) ) {
2015-06-24 23:27:56 +02:00
LogPrintf ( " CConsensusVote::Sign() - Sign message failed " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
if ( ! darkSendSigner . VerifyMessage ( pubkey2 , vchMasterNodeSignature , strMessage , errorMessage ) ) {
2015-06-24 23:27:56 +02:00
LogPrintf ( " CConsensusVote::Sign() - Verify message failed " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
return true ;
}
bool CTransactionLock : : SignaturesValid ( )
{
BOOST_FOREACH ( CConsensusVote vote , vecConsensusVotes )
{
2015-02-23 21:01:21 +01:00
int n = mnodeman . GetMasternodeRank ( vote . vinMasternode , vote . nBlockHeight , MIN_INSTANTX_PROTO_VERSION ) ;
2014-12-09 02:17:57 +01:00
2014-12-31 03:54:00 +01:00
if ( n = = - 1 )
2014-12-09 02:17:57 +01:00
{
2015-06-24 23:27:56 +02:00
LogPrintf ( " CTransactionLock::SignaturesValid() - Unknown Masternode \n " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
2015-02-05 18:56:11 +01:00
if ( n > INSTANTX_SIGNATURES_TOTAL )
2014-12-09 02:17:57 +01:00
{
2015-06-24 23:27:56 +02:00
LogPrintf ( " CTransactionLock::SignaturesValid() - Masternode not in the top %s \n " , INSTANTX_SIGNATURES_TOTAL ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
if ( ! vote . SignatureValid ( ) ) {
2015-06-24 23:27:56 +02:00
LogPrintf ( " CTransactionLock::SignaturesValid() - Signature not valid \n " ) ;
2014-12-09 02:17:57 +01:00
return false ;
}
}
return true ;
}
2015-02-06 20:07:22 +01:00
void CTransactionLock : : AddSignature ( CConsensusVote & cv )
2014-12-09 02:17:57 +01:00
{
vecConsensusVotes . push_back ( cv ) ;
}
int CTransactionLock : : CountSignatures ( )
{
2015-02-04 22:09:50 +01:00
/*
Only count signatures where the BlockHeight matches the transaction ' s blockheight .
The votes have no proof it ' s the correct blockheight
*/
2015-02-05 05:05:36 +01:00
if ( nBlockHeight = = 0 ) return - 1 ;
2015-02-04 22:09:50 +01:00
int n = 0 ;
BOOST_FOREACH ( CConsensusVote v , vecConsensusVotes ) {
if ( v . nBlockHeight = = nBlockHeight ) {
n + + ;
}
}
return n ;
2014-12-06 20:41:53 +01:00
}