20 #include <boost/algorithm/string/replace.hpp> 21 #include <boost/thread.hpp> 87 BOOST_FOREACH(
const CTxIn& txin, txLockRequest.
vin) {
91 LogPrintf(
"CInstantSend::ProcessTxLockRequest -- WARNING: Found conflicting completed Transaction Lock, txid=%s, completed lock txid=%s\n",
98 BOOST_FOREACH(
const CTxIn& txin, txLockRequest.
vin) {
101 BOOST_FOREACH(
const uint256& hash, it->second) {
102 if(hash != txLockRequest.
GetHash()) {
113 LogPrintf(
"CInstantSend::ProcessTxLockRequest -- CreateTxLockCandidate failed, txid=%s\n", txHash.
ToString());
116 LogPrintf(
"CInstantSend::ProcessTxLockRequest -- accepted, txid=%s\n", txHash.
ToString());
118 std::map<uint256, CTxLockCandidate>::iterator itLockCandidate =
mapTxLockCandidates.find(txHash);
120 Vote(txLockCandidate, connman);
133 if(!txLockRequest.
IsValid())
return false;
139 std::map<uint256, CTxLockCandidate>::iterator itLockCandidate =
mapTxLockCandidates.find(txHash);
141 LogPrintf(
"CInstantSend::CreateTxLockCandidate -- new, txid=%s\n", txHash.
ToString());
145 BOOST_REVERSE_FOREACH(
const CTxIn& txin, txLockRequest.
vin) {
146 txLockCandidate.AddOutPointLock(txin.
prevout);
149 }
else if (!itLockCandidate->second.txLockRequest) {
151 itLockCandidate->second.txLockRequest = txLockRequest;
152 if (itLockCandidate->second.IsTimedOut()) {
153 LogPrintf(
"CInstantSend::CreateTxLockCandidate -- timed out, txid=%s\n", txHash.
ToString());
156 LogPrintf(
"CInstantSend::CreateTxLockCandidate -- update empty, txid=%s\n", txHash.
ToString());
159 BOOST_REVERSE_FOREACH(
const CTxIn& txin, txLockRequest.
vin) {
160 itLockCandidate->second.AddOutPointLock(txin.
prevout);
163 LogPrint(
"instantsend",
"CInstantSend::CreateTxLockCandidate -- seen, txid=%s\n", txHash.
ToString());
173 LogPrintf(
"CInstantSend::CreateEmptyTxLockCandidate -- new, txid=%s\n", txHash.
ToString());
188 std::map<COutPoint, COutPointLock>::iterator itOutpointLock = txLockCandidate.
mapOutPointLocks.begin();
192 if(nPrevoutHeight == -1) {
193 LogPrint(
"instantsend",
"CInstantSend::Vote -- Failed to find UTXO %s\n", itOutpointLock->first.ToStringShort());
197 int nLockInputHeight = nPrevoutHeight + 4;
207 if(nRank > nSignaturesTotal) {
208 LogPrint(
"instantsend",
"CInstantSend::Vote -- Masternode not in the top %d (%d)\n", nSignaturesTotal, nRank);
213 LogPrint(
"instantsend",
"CInstantSend::Vote -- In the top %d (%d)\n", nSignaturesTotal, nRank);
215 std::map<COutPoint, std::set<uint256> >::iterator itVoted =
mapVotedOutpoints.find(itOutpointLock->first);
219 bool fAlreadyVoted =
false;
221 BOOST_FOREACH(
const uint256& hash, itVoted->second) {
226 fAlreadyVoted =
true;
227 LogPrintf(
"CInstantSend::Vote -- WARNING: We already voted for this outpoint, skipping: txHash=%s, outpoint=%s\n",
228 txHash.
ToString(), itOutpointLock->first.ToStringShort());
242 LogPrintf(
"CInstantSend::Vote -- Failed to sign consensus vote\n");
246 LogPrintf(
"CInstantSend::Vote -- Signature invalid\n");
253 if(itOutpointLock->second.AddVote(vote)) {
254 LogPrintf(
"CInstantSend::Vote -- Vote created successfully, relaying: txHash=%s, outpoint=%s, vote=%s\n",
255 txHash.
ToString(), itOutpointLock->first.ToStringShort(), nVoteHash.
ToString());
258 std::set<uint256> setHashes;
259 setHashes.insert(txHash);
265 LogPrintf(
"CInstantSend::Vote -- WARNING: Vote conflicts with some existing votes: txHash=%s, outpoint=%s, vote=%s\n",
266 txHash.
ToString(), itOutpointLock->first.ToStringShort(), nVoteHash.
ToString());
290 if(!vote.
IsValid(pfrom, connman)) {
292 LogPrint(
"instantsend",
"CInstantSend::ProcessTxLockVote -- Vote is invalid, txid=%s\n", txHash.
ToString());
308 LogPrint(
"instantsend",
"CInstantSend::ProcessTxLockVote -- Orphan vote: txid=%s masternode=%s new\n",
310 bool fReprocess =
true;
322 LogPrint(
"instantsend",
"CInstantSend::ProcessTxLockVote -- Found enough orphan votes, reprocessing Transaction Lock Request: txid=%s\n", txHash.
ToString());
327 LogPrint(
"instantsend",
"CInstantSend::ProcessTxLockVote -- Orphan vote: txid=%s masternode=%s seen\n",
334 int nMasternodeOrphanExpireTime =
GetTime() + 60*10;
340 LogPrint(
"instantsend",
"CInstantSend::ProcessTxLockVote -- masternode is spamming orphan Transaction Lock Votes: txid=%s masternode=%s\n",
355 LogPrint(
"instantsend",
"CInstantSend::ProcessTxLockVote -- too late, Transaction Lock timed out, txid=%s\n", txHash.
ToString());
359 LogPrint(
"instantsend",
"CInstantSend::ProcessTxLockVote -- Transaction Lock Vote, txid=%s\n", txHash.
ToString());
363 BOOST_FOREACH(
const uint256& hash, it1->second) {
376 it2->second.MarkOutpointAsAttacked(vote.
GetOutpoint());
386 it1->second.insert(txHash);
388 std::set<uint256> setHashes;
389 setHashes.insert(txHash);
393 if(!txLockCandidate.
AddVote(vote)) {
398 int nSignatures = txLockCandidate.
CountVotes();
400 LogPrint(
"instantsend",
"CInstantSend::ProcessTxLockVote -- Transaction Lock signatures count: %d/%d, vote hash=%s\n",
432 BOOST_FOREACH(
const CTxIn& txin, txLockRequest.
vin) {
447 if(it->second.GetTxHash() == txHash && it->second.GetOutpoint() == outpoint) {
472 LogPrint(
"instantsend",
"CInstantSend::TryToFinalizeLockCandidate -- Transaction Lock is ready to complete, txid=%s\n", txHash.
ToString());
498 std::string strCmd =
GetArg(
"-instantsendnotify",
"");
499 if(!strCmd.empty()) {
500 boost::replace_all(strCmd,
"%s", txHash.
GetHex());
508 LogPrint(
"instantsend",
"CInstantSend::UpdateLockedTransaction -- done, txid=%s\n", txHash.
ToString());
521 std::map<COutPoint, COutPointLock>::const_iterator it = txLockCandidate.
mapOutPointLocks.begin();
527 LogPrint(
"instantsend",
"CInstantSend::LockTransactionInputs -- done, txid=%s\n", txHash.
ToString());
535 hashRet = it->second;
555 std::map<uint256, CTxLockCandidate>::iterator itLockCandidate =
mapTxLockCandidates.find(txHash);
556 std::map<uint256, CTxLockCandidate>::iterator itLockCandidateConflicting =
mapTxLockCandidates.find(hashConflicting);
559 LogPrintf(
"CInstantSend::ResolveConflicts -- ERROR: Found conflicting completed Transaction Lock, but one of txLockCandidate-s is missing, txid=%s, conflicting txid=%s\n",
563 LogPrintf(
"CInstantSend::ResolveConflicts -- WARNING: Found conflicting completed Transaction Lock, dropping both, txid=%s, conflicting txid=%s\n",
565 CTxLockRequest txLockRequest = itLockCandidate->second.txLockRequest;
566 CTxLockRequest txLockRequestConflicting = itLockCandidateConflicting->second.txLockRequest;
567 itLockCandidate->second.SetConfirmedHeight(0);
568 itLockCandidateConflicting->second.SetConfirmedHeight(0);
587 if(txHash == hashConflicting)
continue;
589 LogPrintf(
"CInstantSend::ResolveConflicts -- ERROR: Failed to complete Transaction Lock, conflicts with mempool, txid=%s\n", txHash.
ToString());
597 LogPrint(
"instantsend",
"CInstantSend::ResolveConflicts -- Done, %s is included in block %s\n", txHash.
ToString(), hashBlock.
ToString());
605 LogPrintf(
"CInstantSend::ResolveConflicts -- ERROR: Failed to find UTXO %s, can't complete Transaction Lock\n", txin.
prevout.
ToStringShort());
609 LogPrint(
"instantsend",
"CInstantSend::ResolveConflicts -- Done, txid=%s\n", txHash.
ToString());
637 std::map<uint256, CTxLockCandidate>::iterator itLockCandidate =
mapTxLockCandidates.begin();
644 LogPrintf(
"CInstantSend::CheckAndRemove -- Removing expired Transaction Lock Candidate: txid=%s\n", txHash.
ToString());
645 std::map<COutPoint, COutPointLock>::iterator itOutpointLock = txLockCandidate.
mapOutPointLocks.begin();
660 std::map<uint256, CTxLockVote>::iterator itVote =
mapTxLockVotes.begin();
663 LogPrint(
"instantsend",
"CInstantSend::CheckAndRemove -- Removing expired vote: txid=%s masternode=%s\n",
664 itVote->second.GetTxHash().ToString(), itVote->second.GetMasternodeOutpoint().ToStringShort());
674 if(itOrphanVote->second.IsTimedOut()) {
675 LogPrint(
"instantsend",
"CInstantSend::CheckAndRemove -- Removing timed out orphan vote: txid=%s masternode=%s\n",
676 itOrphanVote->second.GetTxHash().ToString(), itOrphanVote->second.GetMasternodeOutpoint().ToStringShort());
687 if(itVote->second.IsFailed()) {
688 LogPrint(
"instantsend",
"CInstantSend::CheckAndRemove -- Removing vote for failed lock attempt: txid=%s masternode=%s\n",
689 itVote->second.GetTxHash().ToString(), itVote->second.GetMasternodeOutpoint().ToStringShort());
699 if(itMasternodeOrphan->second <
GetTime()) {
700 LogPrint(
"instantsend",
"CInstantSend::CheckAndRemove -- Removing timed out orphan masternode vote: masternode=%s\n",
701 itMasternodeOrphan->first.ToStringShort());
704 ++itMasternodeOrphan;
742 txLockRequestRet = it->second.txLockRequest;
751 std::map<uint256, CTxLockVote>::iterator it =
mapTxLockVotes.find(hash);
753 txLockVoteRet = it->second;
778 std::map<uint256, CTxLockCandidate>::iterator itLockCandidate =
mapTxLockCandidates.find(txHash);
782 if(itLockCandidate->second.mapOutPointLocks.empty())
return false;
785 std::map<COutPoint, COutPointLock>::iterator itOutpointLock = itLockCandidate->second.mapOutPointLocks.begin();
786 while(itOutpointLock != itLockCandidate->second.mapOutPointLocks.end()) {
803 std::map<uint256, CTxLockCandidate>::iterator itLockCandidate =
mapTxLockCandidates.find(txHash);
805 return itLockCandidate->second.CountVotes();
822 std::map<uint256, CTxLockCandidate>::iterator itLockCandidate =
mapTxLockCandidates.find(txHash);
824 return !itLockCandidate->second.IsAllOutPointsReady() &&
825 itLockCandidate->second.IsTimedOut();
835 std::map<uint256, CTxLockCandidate>::const_iterator itLockCandidate =
mapTxLockCandidates.find(txHash);
837 itLockCandidate->second.Relay(connman);
864 LogPrint(
"instantsend",
"CTxLockRequest::SyncTransaction -- Failed to find block %s\n", blockHash.
ToString());
867 pblockindex = mi->second;
869 int nHeightNew = pblockindex ? pblockindex->
nHeight : -1;
871 LogPrint(
"instantsend",
"CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d\n", txHash.
ToString(), nHeightNew);
874 std::map<uint256, CTxLockCandidate>::iterator itLockCandidate =
mapTxLockCandidates.find(txHash);
876 LogPrint(
"instantsend",
"CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d lock candidate updated\n",
878 itLockCandidate->second.SetConfirmedHeight(nHeightNew);
880 std::map<COutPoint, COutPointLock>::iterator itOutpointLock = itLockCandidate->second.mapOutPointLocks.begin();
881 while(itOutpointLock != itLockCandidate->second.mapOutPointLocks.end()) {
883 std::vector<CTxLockVote> vVotes = itOutpointLock->second.GetVotes();
884 std::vector<CTxLockVote>::iterator itVote = vVotes.begin();
885 std::map<uint256, CTxLockVote>::iterator it;
886 while(itVote != vVotes.end()) {
888 LogPrint(
"instantsend",
"CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d vote %s updated\n",
892 it->second.SetConfirmedHeight(nHeightNew);
903 if(itOrphanVote->second.GetTxHash() == txHash) {
904 LogPrint(
"instantsend",
"CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d vote %s updated\n",
905 txHash.
ToString(), nHeightNew, itOrphanVote->first.ToString());
906 mapTxLockVotes[itOrphanVote->first].SetConfirmedHeight(nHeightNew);
924 if(
vout.size() < 1)
return false;
927 LogPrint(
"instantsend",
"CTxLockRequest::IsValid -- WARNING: Too many inputs: tx=%s",
ToString());
932 LogPrint(
"instantsend",
"CTxLockRequest::IsValid -- Transaction is not final: tx=%s",
ToString());
943 LogPrint(
"instantsend",
"CTxLockRequest::IsValid -- Invalid Script %s",
ToString());
946 nValueOut += txout.
nValue;
949 BOOST_FOREACH(
const CTxIn& txin,
vin) {
962 if(nTxAge < nConfirmationsRequired) {
963 LogPrint(
"instantsend",
"CTxLockRequest::IsValid -- outpoint %s too new: nTxAge=%d, nConfirmationsRequired=%d, txid=%s\n",
972 LogPrint(
"instantsend",
"CTxLockRequest::IsValid -- Transaction value too high: nValueIn=%d, tx=%s", nValueIn,
ToString());
977 LogPrint(
"instantsend",
"CTxLockRequest::IsValid -- did not include enough fees in transaction: fees=%d, tx=%s", nValueOut - nValueIn,
ToString());
987 return std::max(nMinFee,
CAmount(
vin.size() * nMinFee));
1013 int nLockInputHeight = coins.
nHeight + 4;
1024 if(nRank > nSignaturesTotal) {
1025 LogPrint(
"instantsend",
"CTxLockVote::IsValid -- Masternode %s is not in the top %d (%d), vote hash=%s\n",
1031 LogPrintf(
"CTxLockVote::IsValid -- Signature invalid\n");
1049 std::string strError;
1060 LogPrintf(
"CTxLockVote::CheckSignature -- VerifyMessage() failed, error: %s\n", strError);
1069 std::string strError;
1073 LogPrintf(
"CTxLockVote::Sign -- SignMessage() failed\n");
1078 LogPrintf(
"CTxLockVote::Sign -- VerifyMessage() failed, error: %s\n", strError);
1121 std::vector<CTxLockVote> vRet;
1122 std::map<COutPoint, CTxLockVote>::const_iterator itVote =
mapMasternodeVotes.begin();
1124 vRet.push_back(itVote->second);
1137 std::map<COutPoint, CTxLockVote>::const_iterator itVote =
mapMasternodeVotes.begin();
1139 itVote->second.Relay(connman);
1155 std::map<COutPoint, COutPointLock>::iterator it =
mapOutPointLocks.find(outpoint);
1157 it->second.MarkAsAttacked();
1164 return it->second.AddVote(vote);
1171 std::map<COutPoint, COutPointLock>::const_iterator it =
mapOutPointLocks.begin();
1173 if(!it->second.IsReady())
return false;
1181 std::map<COutPoint, COutPointLock>::iterator it =
mapOutPointLocks.find(outpointIn);
1182 return it !=
mapOutPointLocks.end() && it->second.HasMasternodeVoted(outpointMasternodeIn);
1188 int nCountVotes = 0;
1189 std::map<COutPoint, COutPointLock>::const_iterator it =
mapOutPointLocks.begin();
1191 nCountVotes += it->second.CountVotes();
1211 std::map<COutPoint, COutPointLock>::const_iterator itOutpointLock =
mapOutPointLocks.begin();
1213 itOutpointLock->second.Relay(connman);
static const int INSTANTSEND_CONFIRMATIONS_REQUIRED
void UpdateLockedTransaction(const CTxLockCandidate &txLockCandidate)
static const CAmount MIN_FEE
boost::signals2::signal< void(const CTransaction &)> NotifyTransactionLock
COutPoint outpointMasternode
int64_t GetAverageMasternodeOrphanVoteTime()
void TryToFinalizeLockCandidate(const CTxLockCandidate &txLockCandidate)
CMasternodeSync masternodeSync
std::set< uint256 > setAskFor
void RelayTransaction(const CTransaction &tx)
CActiveMasternode activeMasternode
bool IsTxLockCandidateTimedOut(const uint256 &txHash)
bool GetLockedOutPointTxHash(const COutPoint &outpoint, uint256 &hashRet)
int GetUTXOHeight(const COutPoint &outpoint)
bool GetTxLockVote(const uint256 &hash, CTxLockVote &txLockVoteRet)
std::map< uint256, CTxLockVote > mapTxLockVotesOrphan
static const int SPORK_3_INSTANTSEND_BLOCK_FILTERING
bool IsExpired(int nHeight) const
void AcceptLockRequest(const CTxLockRequest &txLockRequest)
bool IsAllOutPointsReady() const
static const int SPORK_5_INSTANTSEND_MAX_VALUE
bool IsEnoughOrphanVotesForTxAndOutPoint(const uint256 &txHash, const COutPoint &outpoint)
uint64_t GetHash(const uint256 &salt) const
bool GetUTXOCoins(const COutPoint &outpoint, CCoins &coins)
void UpdatedBlockTip(const CBlockIndex *pindex)
CCriticalSection cs_wallet
static const int SIGNATURES_REQUIRED
static const int DEFAULT_INSTANTSEND_DEPTH
std::map< COutPoint, COutPointLock > mapOutPointLocks
const Consensus::Params & GetConsensus() const
static const CAmount COIN
void Relay(const uint256 &txHash, CConnman &connman)
bool CreateTxLockCandidate(const CTxLockRequest &txLockRequest)
std::map< uint256, CTxLockVote > mapTxLockVotes
std::map< COutPoint, CInPoint > mapNextTx
static const int SIGNATURES_TOTAL
void RelayInv(CInv &inv, const int minProtoVersion=MIN_PEER_PROTO_VERSION)
bool HasMasternodeVoted(const COutPoint &outpointMasternodeIn) const
bool AlreadyHave(const uint256 &hash)
void AskForMN(CNode *pnode, const COutPoint &outpoint, CConnman &connman)
Ask (source) node for mnb.
void Relay(CConnman &connman) const
std::map< uint256, CTxLockRequest > mapLockRequestRejected
bool AddVote(const CTxLockVote &vote)
void ProcessOrphanTxLockVotes(CConnman &connman)
uint256 GetTxHash() const
COutPoint GetOutpoint() const
void Relay(CConnman &connman) const
std::map< COutPoint, uint256 > mapLockedOutpoints
bool UpdatedTransaction(const uint256 &hashTx)
void RejectLockRequest(const CTxLockRequest &txLockRequest)
#define AssertLockHeld(cs)
bool IsUnspendable() const
std::vector< CTxOut > vout
unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are d...
std::map< COutPoint, CTxLockVote > mapMasternodeVotes
bool fLargeWorkInvalidChainFound
bool IsInstantSendReadyToLock(const uint256 &txHash)
bool CheckFinalTx(const CTransaction &tx, int flags)
int GetTransactionLockSignatures(const uint256 &txHash)
void Vote(CTxLockCandidate &txLockCandidate, CConnman &connman)
CCriticalSection cs_instantsend
CTxLockRequest txLockRequest
static int LogPrint(const char *category, const char *format)
int GetConfirmations(const uint256 &nTXHash)
static const int INSTANTSEND_FAILED_TIMEOUT_SECONDS
bool GetMasternodeInfo(const COutPoint &outpoint, masternode_info_t &mnInfoRet)
bool IsNormalPaymentScript() const
COutPoint GetMasternodeOutpoint() const
void ProcessMessage(CNode *pfrom, std::string &strCommand, CDataStream &vRecv, CConnman &connman)
std::atomic< bool > fDIP0001ActiveAtTip
CMainSignals & GetMainSignals()
std::map< COutPoint, int64_t > mapMasternodeOrphanVotes
static bool VerifyMessage(const CPubKey pubkey, const std::vector< unsigned char > &vchSig, const std::string strMessage, std::string &strErrorRet)
Verify the message signature, returns true if succcessful.
bool IsLockedInstantSendTransaction(const uint256 &txHash)
std::string ToString() const
bool IsValid(CNode *pnode, CConnman &connman) const
std::map< uint256, CTxLockCandidate > mapTxLockCandidates
CSporkManager sporkManager
const std::vector< CTxIn > vin
bool CheckSignature() const
bool IsExpired(int nHeight) const
std::string ToString() const
void Relay(CConnman &connman) const
const CChainParams & Params()
static const int PROTOCOL_VERSION
const uint256 & GetHash() const
CAmount GetMinFee() const
std::map< COutPoint, std::set< uint256 > > mapVotedOutpoints
bool ProcessTxLockRequest(const CTxLockRequest &txLockRequest, CConnman &connman)
void runCommand(const std::string &strCommand)
std::string ToString() const
bool ProcessTxLockVote(CNode *pfrom, CTxLockVote &vote, CConnman &connman)
std::string GetHex() const
bool AddVote(const CTxLockVote &vote)
std::vector< unsigned char > vchMasternodeSignature
const std::vector< CTxOut > vout
bool PoSeBan(const COutPoint &outpoint)
bool Has(const COutPoint &outpoint)
bool GetMasternodeRank(const COutPoint &outpoint, int &nRankRet, int nBlockHeight=-1, int nMinProtocol=0)
static bool SignMessage(const std::string strMessage, std::vector< unsigned char > &vchSigRet, const CKey key)
Sign the message, returns true if successful.
bool HasTxLockRequest(const uint256 &txHash)
static const int INSTANTSEND_LOCK_TIMEOUT_SECONDS
std::string GetArg(const std::string &strArg, const std::string &strDefault)
bool GetTxLockRequest(const uint256 &txHash, CTxLockRequest &txLockRequestRet)
static const int WARN_MANY_INPUTS
void AddOutPointLock(const COutPoint &outpoint)
void MarkOutpointAsAttacked(const COutPoint &outpoint)
bool IsSporkActive(int nSporkID)
int64_t GetTime()
For unit testing.
static const int MIN_INSTANTSEND_PROTO_VERSION
bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params &consensusParams, uint256 &hashBlock, bool fAllowSlow)
bool IsEnoughOrphanVotesForTx(const CTxLockRequest &txLockRequest)
std::vector< CTxLockVote > GetVotes() const
void SyncTransaction(const CTransaction &tx, const CBlock *pblock)
int GetMaxSignatures() const
int64_t GetSporkValue(int nSporkID)
std::map< uint256, CTxLockRequest > mapLockRequestAccepted
void LockTransactionInputs(const CTxLockCandidate &txLockCandidate)
int nHeight
height of the entry in the chain. The genesis block has height 0
std::string ToStringShort() const
static const int SPORK_2_INSTANTSEND_ENABLED
bool IsMasternodeListSynced()
std::atomic< int > nVersion
bool ResolveConflicts(const CTxLockCandidate &txLockCandidate)
int nHeight
at which height this transaction was included in the active block chain
void CreateEmptyTxLockCandidate(const uint256 &txHash)
bool HasMasternodeVoted(const COutPoint &outpointIn, const COutPoint &outpointMasternodeIn)