Dash Core  0.12.2.1
P2P Digital Currency
instantx.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2017 The Dash Core developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include "activemasternode.h"
6 #include "instantx.h"
7 #include "key.h"
8 #include "validation.h"
9 #include "masternode-sync.h"
10 #include "masternodeman.h"
11 #include "messagesigner.h"
12 #include "net.h"
13 #include "protocol.h"
14 #include "spork.h"
15 #include "sync.h"
16 #include "txmempool.h"
17 #include "util.h"
18 #include "consensus/validation.h"
19 
20 #include <boost/algorithm/string/replace.hpp>
21 #include <boost/thread.hpp>
22 
23 extern CWallet* pwalletMain;
24 extern CTxMemPool mempool;
25 
26 bool fEnableInstantSend = true;
29 
31 
32 // Transaction Locks
33 //
34 // step 1) Some node announces intention to lock transaction inputs via "txlreg" message
35 // step 2) Top COutPointLock::SIGNATURES_TOTAL masternodes per each spent outpoint push "txvote" message
36 // step 3) Once there are COutPointLock::SIGNATURES_REQUIRED valid "txvote" messages per each spent outpoint
37 // for a corresponding "txlreg" message, all outpoints from that tx are treated as locked
38 
39 //
40 // CInstantSend
41 //
42 
43 void CInstantSend::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman)
44 {
45  if(fLiteMode) return; // disable all Dash specific functionality
47 
48  // Ignore any InstantSend messages until masternode list is synced
50 
51  // NOTE: NetMsgType::TXLOCKREQUEST is handled via ProcessMessage() in main.cpp
52 
53  if (strCommand == NetMsgType::TXLOCKVOTE) // InstantSend Transaction Lock Consensus Votes
54  {
55  if(pfrom->nVersion < MIN_INSTANTSEND_PROTO_VERSION) return;
56 
57  CTxLockVote vote;
58  vRecv >> vote;
59 
60  LOCK(cs_main);
61 #ifdef ENABLE_WALLET
62  if (pwalletMain)
64 #endif
66 
67  uint256 nVoteHash = vote.GetHash();
68 
69  pfrom->setAskFor.erase(nVoteHash);
70 
71  if(mapTxLockVotes.count(nVoteHash)) return;
72  mapTxLockVotes.insert(std::make_pair(nVoteHash, vote));
73 
74  ProcessTxLockVote(pfrom, vote, connman);
75 
76  return;
77  }
78 }
79 
80 bool CInstantSend::ProcessTxLockRequest(const CTxLockRequest& txLockRequest, CConnman& connman)
81 {
83 
84  uint256 txHash = txLockRequest.GetHash();
85 
86  // Check to see if we conflict with existing completed lock
87  BOOST_FOREACH(const CTxIn& txin, txLockRequest.vin) {
88  std::map<COutPoint, uint256>::iterator it = mapLockedOutpoints.find(txin.prevout);
89  if(it != mapLockedOutpoints.end() && it->second != txLockRequest.GetHash()) {
90  // Conflicting with complete lock, proceed to see if we should cancel them both
91  LogPrintf("CInstantSend::ProcessTxLockRequest -- WARNING: Found conflicting completed Transaction Lock, txid=%s, completed lock txid=%s\n",
92  txLockRequest.GetHash().ToString(), it->second.ToString());
93  }
94  }
95 
96  // Check to see if there are votes for conflicting request,
97  // if so - do not fail, just warn user
98  BOOST_FOREACH(const CTxIn& txin, txLockRequest.vin) {
99  std::map<COutPoint, std::set<uint256> >::iterator it = mapVotedOutpoints.find(txin.prevout);
100  if(it != mapVotedOutpoints.end()) {
101  BOOST_FOREACH(const uint256& hash, it->second) {
102  if(hash != txLockRequest.GetHash()) {
103  LogPrint("instantsend", "CInstantSend::ProcessTxLockRequest -- Double spend attempt! %s\n", txin.prevout.ToStringShort());
104  // do not fail here, let it go and see which one will get the votes to be locked
105  // TODO: notify zmq+script
106  }
107  }
108  }
109  }
110 
111  if(!CreateTxLockCandidate(txLockRequest)) {
112  // smth is not right
113  LogPrintf("CInstantSend::ProcessTxLockRequest -- CreateTxLockCandidate failed, txid=%s\n", txHash.ToString());
114  return false;
115  }
116  LogPrintf("CInstantSend::ProcessTxLockRequest -- accepted, txid=%s\n", txHash.ToString());
117 
118  std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.find(txHash);
119  CTxLockCandidate& txLockCandidate = itLockCandidate->second;
120  Vote(txLockCandidate, connman);
121  ProcessOrphanTxLockVotes(connman);
122 
123  // Masternodes will sometimes propagate votes before the transaction is known to the client.
124  // If this just happened - lock inputs, resolve conflicting locks, update transaction status
125  // forcing external script notification.
126  TryToFinalizeLockCandidate(txLockCandidate);
127 
128  return true;
129 }
130 
132 {
133  if(!txLockRequest.IsValid()) return false;
134 
136 
137  uint256 txHash = txLockRequest.GetHash();
138 
139  std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.find(txHash);
140  if(itLockCandidate == mapTxLockCandidates.end()) {
141  LogPrintf("CInstantSend::CreateTxLockCandidate -- new, txid=%s\n", txHash.ToString());
142 
143  CTxLockCandidate txLockCandidate(txLockRequest);
144  // all inputs should already be checked by txLockRequest.IsValid() above, just use them now
145  BOOST_REVERSE_FOREACH(const CTxIn& txin, txLockRequest.vin) {
146  txLockCandidate.AddOutPointLock(txin.prevout);
147  }
148  mapTxLockCandidates.insert(std::make_pair(txHash, txLockCandidate));
149  } else if (!itLockCandidate->second.txLockRequest) {
150  // i.e. empty Transaction Lock Candidate was created earlier, let's update it with actual data
151  itLockCandidate->second.txLockRequest = txLockRequest;
152  if (itLockCandidate->second.IsTimedOut()) {
153  LogPrintf("CInstantSend::CreateTxLockCandidate -- timed out, txid=%s\n", txHash.ToString());
154  return false;
155  }
156  LogPrintf("CInstantSend::CreateTxLockCandidate -- update empty, txid=%s\n", txHash.ToString());
157 
158  // all inputs should already be checked by txLockRequest.IsValid() above, just use them now
159  BOOST_REVERSE_FOREACH(const CTxIn& txin, txLockRequest.vin) {
160  itLockCandidate->second.AddOutPointLock(txin.prevout);
161  }
162  } else {
163  LogPrint("instantsend", "CInstantSend::CreateTxLockCandidate -- seen, txid=%s\n", txHash.ToString());
164  }
165 
166  return true;
167 }
168 
170 {
171  if (mapTxLockCandidates.find(txHash) != mapTxLockCandidates.end())
172  return;
173  LogPrintf("CInstantSend::CreateEmptyTxLockCandidate -- new, txid=%s\n", txHash.ToString());
174  const CTxLockRequest txLockRequest = CTxLockRequest();
175  mapTxLockCandidates.insert(std::make_pair(txHash, CTxLockCandidate(txLockRequest)));
176 }
177 
178 void CInstantSend::Vote(CTxLockCandidate& txLockCandidate, CConnman& connman)
179 {
180  if(!fMasterNode) return;
182 
184 
185  uint256 txHash = txLockCandidate.GetHash();
186  // check if we need to vote on this candidate's outpoints,
187  // it's possible that we need to vote for several of them
188  std::map<COutPoint, COutPointLock>::iterator itOutpointLock = txLockCandidate.mapOutPointLocks.begin();
189  while(itOutpointLock != txLockCandidate.mapOutPointLocks.end()) {
190 
191  int nPrevoutHeight = GetUTXOHeight(itOutpointLock->first);
192  if(nPrevoutHeight == -1) {
193  LogPrint("instantsend", "CInstantSend::Vote -- Failed to find UTXO %s\n", itOutpointLock->first.ToStringShort());
194  return;
195  }
196 
197  int nLockInputHeight = nPrevoutHeight + 4;
198 
199  int nRank;
201  LogPrint("instantsend", "CInstantSend::Vote -- Can't calculate rank for masternode %s\n", activeMasternode.outpoint.ToStringShort());
202  ++itOutpointLock;
203  continue;
204  }
205 
206  int nSignaturesTotal = COutPointLock::SIGNATURES_TOTAL;
207  if(nRank > nSignaturesTotal) {
208  LogPrint("instantsend", "CInstantSend::Vote -- Masternode not in the top %d (%d)\n", nSignaturesTotal, nRank);
209  ++itOutpointLock;
210  continue;
211  }
212 
213  LogPrint("instantsend", "CInstantSend::Vote -- In the top %d (%d)\n", nSignaturesTotal, nRank);
214 
215  std::map<COutPoint, std::set<uint256> >::iterator itVoted = mapVotedOutpoints.find(itOutpointLock->first);
216 
217  // Check to see if we already voted for this outpoint,
218  // refuse to vote twice or to include the same outpoint in another tx
219  bool fAlreadyVoted = false;
220  if(itVoted != mapVotedOutpoints.end()) {
221  BOOST_FOREACH(const uint256& hash, itVoted->second) {
222  std::map<uint256, CTxLockCandidate>::iterator it2 = mapTxLockCandidates.find(hash);
223  if(it2->second.HasMasternodeVoted(itOutpointLock->first, activeMasternode.outpoint)) {
224  // we already voted for this outpoint to be included either in the same tx or in a competing one,
225  // skip it anyway
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());
229  break;
230  }
231  }
232  }
233  if(fAlreadyVoted) {
234  ++itOutpointLock;
235  continue; // skip to the next outpoint
236  }
237 
238  // we haven't voted for this outpoint yet, let's try to do this now
239  CTxLockVote vote(txHash, itOutpointLock->first, activeMasternode.outpoint);
240 
241  if(!vote.Sign()) {
242  LogPrintf("CInstantSend::Vote -- Failed to sign consensus vote\n");
243  return;
244  }
245  if(!vote.CheckSignature()) {
246  LogPrintf("CInstantSend::Vote -- Signature invalid\n");
247  return;
248  }
249 
250  // vote constructed sucessfully, let's store and relay it
251  uint256 nVoteHash = vote.GetHash();
252  mapTxLockVotes.insert(std::make_pair(nVoteHash, vote));
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());
256 
257  if(itVoted == mapVotedOutpoints.end()) {
258  std::set<uint256> setHashes;
259  setHashes.insert(txHash);
260  mapVotedOutpoints.insert(std::make_pair(itOutpointLock->first, setHashes));
261  } else {
262  mapVotedOutpoints[itOutpointLock->first].insert(txHash);
263  if(mapVotedOutpoints[itOutpointLock->first].size() > 1) {
264  // it's ok to continue, just warn user
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());
267  }
268  }
269 
270  vote.Relay(connman);
271  }
272 
273  ++itOutpointLock;
274  }
275 }
276 
277 //received a consensus vote
279 {
280  // cs_main, cs_wallet and cs_instantsend should be already locked
282 #ifdef ENABLE_WALLET
283  if (pwalletMain)
285 #endif
287 
288  uint256 txHash = vote.GetTxHash();
289 
290  if(!vote.IsValid(pfrom, connman)) {
291  // could be because of missing MN
292  LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Vote is invalid, txid=%s\n", txHash.ToString());
293  return false;
294  }
295 
296  // relay valid vote asap
297  vote.Relay(connman);
298 
299  // Masternodes will sometimes propagate votes before the transaction is known to the client,
300  // will actually process only after the lock request itself has arrived
301 
302  std::map<uint256, CTxLockCandidate>::iterator it = mapTxLockCandidates.find(txHash);
303  if(it == mapTxLockCandidates.end() || !it->second.txLockRequest) {
304  if(!mapTxLockVotesOrphan.count(vote.GetHash())) {
305  // start timeout countdown after the very first vote
307  mapTxLockVotesOrphan[vote.GetHash()] = vote;
308  LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Orphan vote: txid=%s masternode=%s new\n",
309  txHash.ToString(), vote.GetMasternodeOutpoint().ToStringShort());
310  bool fReprocess = true;
311  std::map<uint256, CTxLockRequest>::iterator itLockRequest = mapLockRequestAccepted.find(txHash);
312  if(itLockRequest == mapLockRequestAccepted.end()) {
313  itLockRequest = mapLockRequestRejected.find(txHash);
314  if(itLockRequest == mapLockRequestRejected.end()) {
315  // still too early, wait for tx lock request
316  fReprocess = false;
317  }
318  }
319  if(fReprocess && IsEnoughOrphanVotesForTx(itLockRequest->second)) {
320  // We have enough votes for corresponding lock to complete,
321  // tx lock request should already be received at this stage.
322  LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Found enough orphan votes, reprocessing Transaction Lock Request: txid=%s\n", txHash.ToString());
323  ProcessTxLockRequest(itLockRequest->second, connman);
324  return true;
325  }
326  } else {
327  LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Orphan vote: txid=%s masternode=%s seen\n",
328  txHash.ToString(), vote.GetMasternodeOutpoint().ToStringShort());
329  }
330 
331  // This tracks those messages and allows only the same rate as of the rest of the network
332  // TODO: make sure this works good enough for multi-quorum
333 
334  int nMasternodeOrphanExpireTime = GetTime() + 60*10; // keep time data for 10 minutes
336  mapMasternodeOrphanVotes[vote.GetMasternodeOutpoint()] = nMasternodeOrphanExpireTime;
337  } else {
338  int64_t nPrevOrphanVote = mapMasternodeOrphanVotes[vote.GetMasternodeOutpoint()];
339  if(nPrevOrphanVote > GetTime() && nPrevOrphanVote > GetAverageMasternodeOrphanVoteTime()) {
340  LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- masternode is spamming orphan Transaction Lock Votes: txid=%s masternode=%s\n",
341  txHash.ToString(), vote.GetMasternodeOutpoint().ToStringShort());
342  // Misbehaving(pfrom->id, 1);
343  return false;
344  }
345  // not spamming, refresh
346  mapMasternodeOrphanVotes[vote.GetMasternodeOutpoint()] = nMasternodeOrphanExpireTime;
347  }
348 
349  return true;
350  }
351 
352  CTxLockCandidate& txLockCandidate = it->second;
353 
354  if (txLockCandidate.IsTimedOut()) {
355  LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- too late, Transaction Lock timed out, txid=%s\n", txHash.ToString());
356  return false;
357  }
358 
359  LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Transaction Lock Vote, txid=%s\n", txHash.ToString());
360 
361  std::map<COutPoint, std::set<uint256> >::iterator it1 = mapVotedOutpoints.find(vote.GetOutpoint());
362  if(it1 != mapVotedOutpoints.end()) {
363  BOOST_FOREACH(const uint256& hash, it1->second) {
364  if(hash != txHash) {
365  // same outpoint was already voted to be locked by another tx lock request,
366  // let's see if it was the same masternode who voted on this outpoint
367  // for another tx lock request
368  std::map<uint256, CTxLockCandidate>::iterator it2 = mapTxLockCandidates.find(hash);
369  if(it2 !=mapTxLockCandidates.end() && it2->second.HasMasternodeVoted(vote.GetOutpoint(), vote.GetMasternodeOutpoint())) {
370  // yes, it was the same masternode
371  LogPrintf("CInstantSend::ProcessTxLockVote -- masternode sent conflicting votes! %s\n", vote.GetMasternodeOutpoint().ToStringShort());
372  // mark both Lock Candidates as attacked, none of them should complete,
373  // or at least the new (current) one shouldn't even
374  // if the second one was already completed earlier
375  txLockCandidate.MarkOutpointAsAttacked(vote.GetOutpoint());
376  it2->second.MarkOutpointAsAttacked(vote.GetOutpoint());
377  // apply maximum PoSe ban score to this masternode i.e. PoSe-ban it instantly
379  // NOTE: This vote must be relayed further to let all other nodes know about such
380  // misbehaviour of this masternode. This way they should also be able to construct
381  // conflicting lock and PoSe-ban this masternode.
382  }
383  }
384  }
385  // store all votes, regardless of them being sent by malicious masternode or not
386  it1->second.insert(txHash);
387  } else {
388  std::set<uint256> setHashes;
389  setHashes.insert(txHash);
390  mapVotedOutpoints.insert(std::make_pair(vote.GetOutpoint(), setHashes));
391  }
392 
393  if(!txLockCandidate.AddVote(vote)) {
394  // this should never happen
395  return false;
396  }
397 
398  int nSignatures = txLockCandidate.CountVotes();
399  int nSignaturesMax = txLockCandidate.txLockRequest.GetMaxSignatures();
400  LogPrint("instantsend", "CInstantSend::ProcessTxLockVote -- Transaction Lock signatures count: %d/%d, vote hash=%s\n",
401  nSignatures, nSignaturesMax, vote.GetHash().ToString());
402 
403  TryToFinalizeLockCandidate(txLockCandidate);
404 
405  return true;
406 }
407 
409 {
410  LOCK(cs_main);
411 #ifdef ENABLE_WALLET
412  if (pwalletMain)
414 #endif
416 
417  std::map<uint256, CTxLockVote>::iterator it = mapTxLockVotesOrphan.begin();
418  while(it != mapTxLockVotesOrphan.end()) {
419  if(ProcessTxLockVote(NULL, it->second, connman)) {
420  mapTxLockVotesOrphan.erase(it++);
421  } else {
422  ++it;
423  }
424  }
425 }
426 
428 {
429  // There could be a situation when we already have quite a lot of votes
430  // but tx lock request still wasn't received. Let's scan through
431  // orphan votes to check if this is the case.
432  BOOST_FOREACH(const CTxIn& txin, txLockRequest.vin) {
433  if(!IsEnoughOrphanVotesForTxAndOutPoint(txLockRequest.GetHash(), txin.prevout)) {
434  return false;
435  }
436  }
437  return true;
438 }
439 
441 {
442  // Scan orphan votes to check if this outpoint has enough orphan votes to be locked in some tx.
444  int nCountVotes = 0;
445  std::map<uint256, CTxLockVote>::iterator it = mapTxLockVotesOrphan.begin();
446  while(it != mapTxLockVotesOrphan.end()) {
447  if(it->second.GetTxHash() == txHash && it->second.GetOutpoint() == outpoint) {
448  nCountVotes++;
449  if(nCountVotes >= COutPointLock::SIGNATURES_REQUIRED) {
450  return true;
451  }
452  }
453  ++it;
454  }
455  return false;
456 }
457 
459 {
461 
462  LOCK(cs_main);
463 #ifdef ENABLE_WALLET
464  if (pwalletMain)
466 #endif
468 
469  uint256 txHash = txLockCandidate.txLockRequest.GetHash();
470  if(txLockCandidate.IsAllOutPointsReady() && !IsLockedInstantSendTransaction(txHash)) {
471  // we have enough votes now
472  LogPrint("instantsend", "CInstantSend::TryToFinalizeLockCandidate -- Transaction Lock is ready to complete, txid=%s\n", txHash.ToString());
473  if(ResolveConflicts(txLockCandidate)) {
474  LockTransactionInputs(txLockCandidate);
475  UpdateLockedTransaction(txLockCandidate);
476  }
477  }
478 }
479 
481 {
482  // cs_wallet and cs_instantsend should be already locked
483 #ifdef ENABLE_WALLET
484  if (pwalletMain)
486 #endif
488 
489  uint256 txHash = txLockCandidate.GetHash();
490 
491  if(!IsLockedInstantSendTransaction(txHash)) return; // not a locked tx, do not update/notify
492 
493 #ifdef ENABLE_WALLET
494  if(pwalletMain && pwalletMain->UpdatedTransaction(txHash)) {
495  // bumping this to update UI
497  // notify an external script once threshold is reached
498  std::string strCmd = GetArg("-instantsendnotify", "");
499  if(!strCmd.empty()) {
500  boost::replace_all(strCmd, "%s", txHash.GetHex());
501  boost::thread t(runCommand, strCmd); // thread runs free
502  }
503  }
504 #endif
505 
507 
508  LogPrint("instantsend", "CInstantSend::UpdateLockedTransaction -- done, txid=%s\n", txHash.ToString());
509 }
510 
512 {
514 
516 
517  uint256 txHash = txLockCandidate.GetHash();
518 
519  if(!txLockCandidate.IsAllOutPointsReady()) return;
520 
521  std::map<COutPoint, COutPointLock>::const_iterator it = txLockCandidate.mapOutPointLocks.begin();
522 
523  while(it != txLockCandidate.mapOutPointLocks.end()) {
524  mapLockedOutpoints.insert(std::make_pair(it->first, txHash));
525  ++it;
526  }
527  LogPrint("instantsend", "CInstantSend::LockTransactionInputs -- done, txid=%s\n", txHash.ToString());
528 }
529 
531 {
533  std::map<COutPoint, uint256>::iterator it = mapLockedOutpoints.find(outpoint);
534  if(it == mapLockedOutpoints.end()) return false;
535  hashRet = it->second;
536  return true;
537 }
538 
540 {
542 
543  uint256 txHash = txLockCandidate.GetHash();
544 
545  // make sure the lock is ready
546  if(!txLockCandidate.IsAllOutPointsReady()) return false;
547 
548  LOCK(mempool.cs); // protect mempool.mapNextTx
549 
550  BOOST_FOREACH(const CTxIn& txin, txLockCandidate.txLockRequest.vin) {
551  uint256 hashConflicting;
552  if(GetLockedOutPointTxHash(txin.prevout, hashConflicting) && txHash != hashConflicting) {
553  // completed lock which conflicts with another completed one?
554  // this means that majority of MNs in the quorum for this specific tx input are malicious!
555  std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.find(txHash);
556  std::map<uint256, CTxLockCandidate>::iterator itLockCandidateConflicting = mapTxLockCandidates.find(hashConflicting);
557  if(itLockCandidate == mapTxLockCandidates.end() || itLockCandidateConflicting == mapTxLockCandidates.end()) {
558  // safety check, should never really happen
559  LogPrintf("CInstantSend::ResolveConflicts -- ERROR: Found conflicting completed Transaction Lock, but one of txLockCandidate-s is missing, txid=%s, conflicting txid=%s\n",
560  txHash.ToString(), hashConflicting.ToString());
561  return false;
562  }
563  LogPrintf("CInstantSend::ResolveConflicts -- WARNING: Found conflicting completed Transaction Lock, dropping both, txid=%s, conflicting txid=%s\n",
564  txHash.ToString(), hashConflicting.ToString());
565  CTxLockRequest txLockRequest = itLockCandidate->second.txLockRequest;
566  CTxLockRequest txLockRequestConflicting = itLockCandidateConflicting->second.txLockRequest;
567  itLockCandidate->second.SetConfirmedHeight(0); // expired
568  itLockCandidateConflicting->second.SetConfirmedHeight(0); // expired
569  CheckAndRemove(); // clean up
570  // AlreadyHave should still return "true" for both of them
571  mapLockRequestRejected.insert(make_pair(txHash, txLockRequest));
572  mapLockRequestRejected.insert(make_pair(hashConflicting, txLockRequestConflicting));
573 
574  // TODO: clean up mapLockRequestRejected later somehow
575  // (not a big issue since we already PoSe ban malicious masternodes
576  // and they won't be able to spam)
577  // TODO: ban all malicious masternodes permanently, do not accept anything from them, ever
578 
579  // TODO: notify zmq+script about this double-spend attempt
580  // and let merchant cancel/hold the order if it's not too late...
581 
582  // can't do anything else, fallback to regular txes
583  return false;
584  } else if (mempool.mapNextTx.count(txin.prevout)) {
585  // check if it's in mempool
586  hashConflicting = mempool.mapNextTx[txin.prevout].ptx->GetHash();
587  if(txHash == hashConflicting) continue; // matches current, not a conflict, skip to next txin
588  // conflicts with tx in mempool
589  LogPrintf("CInstantSend::ResolveConflicts -- ERROR: Failed to complete Transaction Lock, conflicts with mempool, txid=%s\n", txHash.ToString());
590  return false;
591  }
592  } // FOREACH
593  // No conflicts were found so far, check to see if it was already included in block
594  CTransaction txTmp;
595  uint256 hashBlock;
596  if(GetTransaction(txHash, txTmp, Params().GetConsensus(), hashBlock, true) && hashBlock != uint256()) {
597  LogPrint("instantsend", "CInstantSend::ResolveConflicts -- Done, %s is included in block %s\n", txHash.ToString(), hashBlock.ToString());
598  return true;
599  }
600  // Not in block yet, make sure all its inputs are still unspent
601  BOOST_FOREACH(const CTxIn& txin, txLockCandidate.txLockRequest.vin) {
602  CCoins coins;
603  if(!GetUTXOCoins(txin.prevout, coins)) {
604  // Not in UTXO anymore? A conflicting tx was mined while we were waiting for votes.
605  LogPrintf("CInstantSend::ResolveConflicts -- ERROR: Failed to find UTXO %s, can't complete Transaction Lock\n", txin.prevout.ToStringShort());
606  return false;
607  }
608  }
609  LogPrint("instantsend", "CInstantSend::ResolveConflicts -- Done, txid=%s\n", txHash.ToString());
610 
611  return true;
612 }
613 
615 {
617  // NOTE: should never actually call this function when mapMasternodeOrphanVotes is empty
618  if(mapMasternodeOrphanVotes.empty()) return 0;
619 
620  std::map<COutPoint, int64_t>::iterator it = mapMasternodeOrphanVotes.begin();
621  int64_t total = 0;
622 
623  while(it != mapMasternodeOrphanVotes.end()) {
624  total+= it->second;
625  ++it;
626  }
627 
628  return total / mapMasternodeOrphanVotes.size();
629 }
630 
632 {
634 
636 
637  std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.begin();
638 
639  // remove expired candidates
640  while(itLockCandidate != mapTxLockCandidates.end()) {
641  CTxLockCandidate &txLockCandidate = itLockCandidate->second;
642  uint256 txHash = txLockCandidate.GetHash();
643  if(txLockCandidate.IsExpired(nCachedBlockHeight)) {
644  LogPrintf("CInstantSend::CheckAndRemove -- Removing expired Transaction Lock Candidate: txid=%s\n", txHash.ToString());
645  std::map<COutPoint, COutPointLock>::iterator itOutpointLock = txLockCandidate.mapOutPointLocks.begin();
646  while(itOutpointLock != txLockCandidate.mapOutPointLocks.end()) {
647  mapLockedOutpoints.erase(itOutpointLock->first);
648  mapVotedOutpoints.erase(itOutpointLock->first);
649  ++itOutpointLock;
650  }
651  mapLockRequestAccepted.erase(txHash);
652  mapLockRequestRejected.erase(txHash);
653  mapTxLockCandidates.erase(itLockCandidate++);
654  } else {
655  ++itLockCandidate;
656  }
657  }
658 
659  // remove expired votes
660  std::map<uint256, CTxLockVote>::iterator itVote = mapTxLockVotes.begin();
661  while(itVote != mapTxLockVotes.end()) {
662  if(itVote->second.IsExpired(nCachedBlockHeight)) {
663  LogPrint("instantsend", "CInstantSend::CheckAndRemove -- Removing expired vote: txid=%s masternode=%s\n",
664  itVote->second.GetTxHash().ToString(), itVote->second.GetMasternodeOutpoint().ToStringShort());
665  mapTxLockVotes.erase(itVote++);
666  } else {
667  ++itVote;
668  }
669  }
670 
671  // remove timed out orphan votes
672  std::map<uint256, CTxLockVote>::iterator itOrphanVote = mapTxLockVotesOrphan.begin();
673  while(itOrphanVote != mapTxLockVotesOrphan.end()) {
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());
677  mapTxLockVotes.erase(itOrphanVote->first);
678  mapTxLockVotesOrphan.erase(itOrphanVote++);
679  } else {
680  ++itOrphanVote;
681  }
682  }
683 
684  // remove invalid votes and votes for failed lock attempts
685  itVote = mapTxLockVotes.begin();
686  while(itVote != mapTxLockVotes.end()) {
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());
690  mapTxLockVotes.erase(itVote++);
691  } else {
692  ++itVote;
693  }
694  }
695 
696  // remove timed out masternode orphan votes (DOS protection)
697  std::map<COutPoint, int64_t>::iterator itMasternodeOrphan = mapMasternodeOrphanVotes.begin();
698  while(itMasternodeOrphan != mapMasternodeOrphanVotes.end()) {
699  if(itMasternodeOrphan->second < GetTime()) {
700  LogPrint("instantsend", "CInstantSend::CheckAndRemove -- Removing timed out orphan masternode vote: masternode=%s\n",
701  itMasternodeOrphan->first.ToStringShort());
702  mapMasternodeOrphanVotes.erase(itMasternodeOrphan++);
703  } else {
704  ++itMasternodeOrphan;
705  }
706  }
707  LogPrintf("CInstantSend::CheckAndRemove -- %s\n", ToString());
708 }
709 
711 {
713  return mapLockRequestAccepted.count(hash) ||
714  mapLockRequestRejected.count(hash) ||
715  mapTxLockVotes.count(hash);
716 }
717 
719 {
721  mapLockRequestAccepted.insert(make_pair(txLockRequest.GetHash(), txLockRequest));
722 }
723 
725 {
727  mapLockRequestRejected.insert(make_pair(txLockRequest.GetHash(), txLockRequest));
728 }
729 
731 {
732  CTxLockRequest txLockRequestTmp;
733  return GetTxLockRequest(txHash, txLockRequestTmp);
734 }
735 
736 bool CInstantSend::GetTxLockRequest(const uint256& txHash, CTxLockRequest& txLockRequestRet)
737 {
739 
740  std::map<uint256, CTxLockCandidate>::iterator it = mapTxLockCandidates.find(txHash);
741  if(it == mapTxLockCandidates.end()) return false;
742  txLockRequestRet = it->second.txLockRequest;
743 
744  return true;
745 }
746 
747 bool CInstantSend::GetTxLockVote(const uint256& hash, CTxLockVote& txLockVoteRet)
748 {
750 
751  std::map<uint256, CTxLockVote>::iterator it = mapTxLockVotes.find(hash);
752  if(it == mapTxLockVotes.end()) return false;
753  txLockVoteRet = it->second;
754 
755  return true;
756 }
757 
759 {
762 
764  // There must be a successfully verified lock request
765  // and all outputs must be locked (i.e. have enough signatures)
766  std::map<uint256, CTxLockCandidate>::iterator it = mapTxLockCandidates.find(txHash);
767  return it != mapTxLockCandidates.end() && it->second.IsAllOutPointsReady();
768 }
769 
771 {
774 
776 
777  // there must be a lock candidate
778  std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.find(txHash);
779  if(itLockCandidate == mapTxLockCandidates.end()) return false;
780 
781  // which should have outpoints
782  if(itLockCandidate->second.mapOutPointLocks.empty()) return false;
783 
784  // and all of these outputs must be included in mapLockedOutpoints with correct hash
785  std::map<COutPoint, COutPointLock>::iterator itOutpointLock = itLockCandidate->second.mapOutPointLocks.begin();
786  while(itOutpointLock != itLockCandidate->second.mapOutPointLocks.end()) {
787  uint256 hashLocked;
788  if(!GetLockedOutPointTxHash(itOutpointLock->first, hashLocked) || hashLocked != txHash) return false;
789  ++itOutpointLock;
790  }
791 
792  return true;
793 }
794 
796 {
797  if(!fEnableInstantSend) return -1;
800 
802 
803  std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.find(txHash);
804  if(itLockCandidate != mapTxLockCandidates.end()) {
805  return itLockCandidate->second.CountVotes();
806  }
807 
808  return -1;
809 }
810 
812 {
814 }
815 
817 {
818  if(!fEnableInstantSend) return false;
819 
821 
822  std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.find(txHash);
823  if (itLockCandidate != mapTxLockCandidates.end()) {
824  return !itLockCandidate->second.IsAllOutPointsReady() &&
825  itLockCandidate->second.IsTimedOut();
826  }
827 
828  return false;
829 }
830 
831 void CInstantSend::Relay(const uint256& txHash, CConnman& connman)
832 {
834 
835  std::map<uint256, CTxLockCandidate>::const_iterator itLockCandidate = mapTxLockCandidates.find(txHash);
836  if (itLockCandidate != mapTxLockCandidates.end()) {
837  itLockCandidate->second.Relay(connman);
838  }
839 }
840 
842 {
843  nCachedBlockHeight = pindex->nHeight;
844 }
845 
846 void CInstantSend::SyncTransaction(const CTransaction& tx, const CBlock* pblock)
847 {
848  // Update lock candidates and votes if corresponding tx confirmed
849  // or went from confirmed to 0-confirmed or conflicted.
850 
851  if (tx.IsCoinBase()) return;
852 
854 
855  uint256 txHash = tx.GetHash();
856 
857  // When tx is 0-confirmed or conflicted, pblock is NULL and nHeightNew should be set to -1
858  CBlockIndex* pblockindex = NULL;
859  if(pblock) {
860  uint256 blockHash = pblock->GetHash();
861  BlockMap::iterator mi = mapBlockIndex.find(blockHash);
862  if(mi == mapBlockIndex.end() || !mi->second) {
863  // shouldn't happen
864  LogPrint("instantsend", "CTxLockRequest::SyncTransaction -- Failed to find block %s\n", blockHash.ToString());
865  return;
866  }
867  pblockindex = mi->second;
868  }
869  int nHeightNew = pblockindex ? pblockindex->nHeight : -1;
870 
871  LogPrint("instantsend", "CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d\n", txHash.ToString(), nHeightNew);
872 
873  // Check lock candidates
874  std::map<uint256, CTxLockCandidate>::iterator itLockCandidate = mapTxLockCandidates.find(txHash);
875  if(itLockCandidate != mapTxLockCandidates.end()) {
876  LogPrint("instantsend", "CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d lock candidate updated\n",
877  txHash.ToString(), nHeightNew);
878  itLockCandidate->second.SetConfirmedHeight(nHeightNew);
879  // Loop through outpoint locks
880  std::map<COutPoint, COutPointLock>::iterator itOutpointLock = itLockCandidate->second.mapOutPointLocks.begin();
881  while(itOutpointLock != itLockCandidate->second.mapOutPointLocks.end()) {
882  // Check corresponding lock votes
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()) {
887  uint256 nVoteHash = itVote->GetHash();
888  LogPrint("instantsend", "CInstantSend::SyncTransaction -- txid=%s nHeightNew=%d vote %s updated\n",
889  txHash.ToString(), nHeightNew, nVoteHash.ToString());
890  it = mapTxLockVotes.find(nVoteHash);
891  if(it != mapTxLockVotes.end()) {
892  it->second.SetConfirmedHeight(nHeightNew);
893  }
894  ++itVote;
895  }
896  ++itOutpointLock;
897  }
898  }
899 
900  // check orphan votes
901  std::map<uint256, CTxLockVote>::iterator itOrphanVote = mapTxLockVotesOrphan.begin();
902  while(itOrphanVote != mapTxLockVotesOrphan.end()) {
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);
907  }
908  ++itOrphanVote;
909  }
910 }
911 
913 {
915  return strprintf("Lock Candidates: %llu, Votes %llu", mapTxLockCandidates.size(), mapTxLockVotes.size());
916 }
917 
918 //
919 // CTxLockRequest
920 //
921 
923 {
924  if(vout.size() < 1) return false;
925 
926  if(vin.size() > WARN_MANY_INPUTS) {
927  LogPrint("instantsend", "CTxLockRequest::IsValid -- WARNING: Too many inputs: tx=%s", ToString());
928  }
929 
930  LOCK(cs_main);
931  if(!CheckFinalTx(*this)) {
932  LogPrint("instantsend", "CTxLockRequest::IsValid -- Transaction is not final: tx=%s", ToString());
933  return false;
934  }
935 
936  CAmount nValueIn = 0;
937  CAmount nValueOut = 0;
938 
939  BOOST_FOREACH(const CTxOut& txout, vout) {
940  // InstantSend supports normal scripts and unspendable (i.e. data) scripts.
941  // TODO: Look into other script types that are normal and can be included
943  LogPrint("instantsend", "CTxLockRequest::IsValid -- Invalid Script %s", ToString());
944  return false;
945  }
946  nValueOut += txout.nValue;
947  }
948 
949  BOOST_FOREACH(const CTxIn& txin, vin) {
950 
951  CCoins coins;
952 
953  if(!GetUTXOCoins(txin.prevout, coins)) {
954  LogPrint("instantsend", "CTxLockRequest::IsValid -- Failed to find UTXO %s\n", txin.prevout.ToStringShort());
955  return false;
956  }
957 
958  int nTxAge = chainActive.Height() - coins.nHeight + 1;
959  // 1 less than the "send IX" gui requires, in case of a block propagating the network at the time
960  int nConfirmationsRequired = INSTANTSEND_CONFIRMATIONS_REQUIRED - 1;
961 
962  if(nTxAge < nConfirmationsRequired) {
963  LogPrint("instantsend", "CTxLockRequest::IsValid -- outpoint %s too new: nTxAge=%d, nConfirmationsRequired=%d, txid=%s\n",
964  txin.prevout.ToStringShort(), nTxAge, nConfirmationsRequired, GetHash().ToString());
965  return false;
966  }
967 
968  nValueIn += coins.vout[txin.prevout.n].nValue;
969  }
970 
972  LogPrint("instantsend", "CTxLockRequest::IsValid -- Transaction value too high: nValueIn=%d, tx=%s", nValueIn, ToString());
973  return false;
974  }
975 
976  if(nValueIn - nValueOut < GetMinFee()) {
977  LogPrint("instantsend", "CTxLockRequest::IsValid -- did not include enough fees in transaction: fees=%d, tx=%s", nValueOut - nValueIn, ToString());
978  return false;
979  }
980 
981  return true;
982 }
983 
985 {
986  CAmount nMinFee = fDIP0001ActiveAtTip ? MIN_FEE / 10 : MIN_FEE;
987  return std::max(nMinFee, CAmount(vin.size() * nMinFee));
988 }
989 
991 {
992  return vin.size() * COutPointLock::SIGNATURES_TOTAL;
993 }
994 
995 //
996 // CTxLockVote
997 //
998 
999 bool CTxLockVote::IsValid(CNode* pnode, CConnman& connman) const
1000 {
1002  LogPrint("instantsend", "CTxLockVote::IsValid -- Unknown masternode %s\n", outpointMasternode.ToStringShort());
1003  mnodeman.AskForMN(pnode, outpointMasternode, connman);
1004  return false;
1005  }
1006 
1007  CCoins coins;
1008  if(!GetUTXOCoins(outpoint, coins)) {
1009  LogPrint("instantsend", "CTxLockVote::IsValid -- Failed to find UTXO %s\n", outpoint.ToStringShort());
1010  return false;
1011  }
1012 
1013  int nLockInputHeight = coins.nHeight + 4;
1014 
1015  int nRank;
1017  //can be caused by past versions trying to vote with an invalid protocol
1018  LogPrint("instantsend", "CTxLockVote::IsValid -- Can't calculate rank for masternode %s\n", outpointMasternode.ToStringShort());
1019  return false;
1020  }
1021  LogPrint("instantsend", "CTxLockVote::IsValid -- Masternode %s, rank=%d\n", outpointMasternode.ToStringShort(), nRank);
1022 
1023  int nSignaturesTotal = COutPointLock::SIGNATURES_TOTAL;
1024  if(nRank > nSignaturesTotal) {
1025  LogPrint("instantsend", "CTxLockVote::IsValid -- Masternode %s is not in the top %d (%d), vote hash=%s\n",
1026  outpointMasternode.ToStringShort(), nSignaturesTotal, nRank, GetHash().ToString());
1027  return false;
1028  }
1029 
1030  if(!CheckSignature()) {
1031  LogPrintf("CTxLockVote::IsValid -- Signature invalid\n");
1032  return false;
1033  }
1034 
1035  return true;
1036 }
1037 
1039 {
1041  ss << txHash;
1042  ss << outpoint;
1043  ss << outpointMasternode;
1044  return ss.GetHash();
1045 }
1046 
1048 {
1049  std::string strError;
1050  std::string strMessage = txHash.ToString() + outpoint.ToStringShort();
1051 
1052  masternode_info_t infoMn;
1053 
1055  LogPrintf("CTxLockVote::CheckSignature -- Unknown Masternode: masternode=%s\n", outpointMasternode.ToString());
1056  return false;
1057  }
1058 
1059  if(!CMessageSigner::VerifyMessage(infoMn.pubKeyMasternode, vchMasternodeSignature, strMessage, strError)) {
1060  LogPrintf("CTxLockVote::CheckSignature -- VerifyMessage() failed, error: %s\n", strError);
1061  return false;
1062  }
1063 
1064  return true;
1065 }
1066 
1068 {
1069  std::string strError;
1070  std::string strMessage = txHash.ToString() + outpoint.ToStringShort();
1071 
1073  LogPrintf("CTxLockVote::Sign -- SignMessage() failed\n");
1074  return false;
1075  }
1076 
1078  LogPrintf("CTxLockVote::Sign -- VerifyMessage() failed, error: %s\n", strError);
1079  return false;
1080  }
1081 
1082  return true;
1083 }
1084 
1085 void CTxLockVote::Relay(CConnman& connman) const
1086 {
1087  CInv inv(MSG_TXLOCK_VOTE, GetHash());
1088  connman.RelayInv(inv);
1089 }
1090 
1091 bool CTxLockVote::IsExpired(int nHeight) const
1092 {
1093  // Locks and votes expire nInstantSendKeepLock blocks after the block corresponding tx was included into.
1094  return (nConfirmedHeight != -1) && (nHeight - nConfirmedHeight > Params().GetConsensus().nInstantSendKeepLock);
1095 }
1096 
1098 {
1100 }
1101 
1103 {
1105 }
1106 
1107 //
1108 // COutPointLock
1109 //
1110 
1112 {
1113  if(mapMasternodeVotes.count(vote.GetMasternodeOutpoint()))
1114  return false;
1115  mapMasternodeVotes.insert(std::make_pair(vote.GetMasternodeOutpoint(), vote));
1116  return true;
1117 }
1118 
1119 std::vector<CTxLockVote> COutPointLock::GetVotes() const
1120 {
1121  std::vector<CTxLockVote> vRet;
1122  std::map<COutPoint, CTxLockVote>::const_iterator itVote = mapMasternodeVotes.begin();
1123  while(itVote != mapMasternodeVotes.end()) {
1124  vRet.push_back(itVote->second);
1125  ++itVote;
1126  }
1127  return vRet;
1128 }
1129 
1130 bool COutPointLock::HasMasternodeVoted(const COutPoint& outpointMasternodeIn) const
1131 {
1132  return mapMasternodeVotes.count(outpointMasternodeIn);
1133 }
1134 
1135 void COutPointLock::Relay(CConnman& connman) const
1136 {
1137  std::map<COutPoint, CTxLockVote>::const_iterator itVote = mapMasternodeVotes.begin();
1138  while(itVote != mapMasternodeVotes.end()) {
1139  itVote->second.Relay(connman);
1140  ++itVote;
1141  }
1142 }
1143 
1144 //
1145 // CTxLockCandidate
1146 //
1147 
1149 {
1150  mapOutPointLocks.insert(make_pair(outpoint, COutPointLock(outpoint)));
1151 }
1152 
1154 {
1155  std::map<COutPoint, COutPointLock>::iterator it = mapOutPointLocks.find(outpoint);
1156  if(it != mapOutPointLocks.end())
1157  it->second.MarkAsAttacked();
1158 }
1159 
1161 {
1162  std::map<COutPoint, COutPointLock>::iterator it = mapOutPointLocks.find(vote.GetOutpoint());
1163  if(it == mapOutPointLocks.end()) return false;
1164  return it->second.AddVote(vote);
1165 }
1166 
1168 {
1169  if(mapOutPointLocks.empty()) return false;
1170 
1171  std::map<COutPoint, COutPointLock>::const_iterator it = mapOutPointLocks.begin();
1172  while(it != mapOutPointLocks.end()) {
1173  if(!it->second.IsReady()) return false;
1174  ++it;
1175  }
1176  return true;
1177 }
1178 
1179 bool CTxLockCandidate::HasMasternodeVoted(const COutPoint& outpointIn, const COutPoint& outpointMasternodeIn)
1180 {
1181  std::map<COutPoint, COutPointLock>::iterator it = mapOutPointLocks.find(outpointIn);
1182  return it !=mapOutPointLocks.end() && it->second.HasMasternodeVoted(outpointMasternodeIn);
1183 }
1184 
1186 {
1187  // Note: do NOT use vote count to figure out if tx is locked, use IsAllOutPointsReady() instead
1188  int nCountVotes = 0;
1189  std::map<COutPoint, COutPointLock>::const_iterator it = mapOutPointLocks.begin();
1190  while(it != mapOutPointLocks.end()) {
1191  nCountVotes += it->second.CountVotes();
1192  ++it;
1193  }
1194  return nCountVotes;
1195 }
1196 
1197 bool CTxLockCandidate::IsExpired(int nHeight) const
1198 {
1199  // Locks and votes expire nInstantSendKeepLock blocks after the block corresponding tx was included into.
1200  return (nConfirmedHeight != -1) && (nHeight - nConfirmedHeight > Params().GetConsensus().nInstantSendKeepLock);
1201 }
1202 
1204 {
1206 }
1207 
1208 void CTxLockCandidate::Relay(CConnman& connman) const
1209 {
1211  std::map<COutPoint, COutPointLock>::const_iterator itOutpointLock = mapOutPointLocks.begin();
1212  while(itOutpointLock != mapOutPointLocks.end()) {
1213  itOutpointLock->second.Relay(connman);
1214  ++itOutpointLock;
1215  }
1216 }
uint32_t n
Definition: transaction.h:19
int nConfirmedHeight
Definition: instantx.h:150
static const int INSTANTSEND_CONFIRMATIONS_REQUIRED
Definition: instantx.h:28
int CountVotes() const
Definition: instantx.cpp:1185
void UpdateLockedTransaction(const CTxLockCandidate &txLockCandidate)
Definition: instantx.cpp:480
static const CAmount MIN_FEE
Definition: instantx.h:124
boost::signals2::signal< void(const CTransaction &)> NotifyTransactionLock
COutPoint outpointMasternode
Definition: instantx.h:147
int64_t GetAverageMasternodeOrphanVoteTime()
Definition: instantx.cpp:614
CMasternodeMan mnodeman
void TryToFinalizeLockCandidate(const CTxLockCandidate &txLockCandidate)
Definition: instantx.cpp:458
CMasternodeSync masternodeSync
int nCompleteTXLocks
Definition: instantx.cpp:28
std::set< uint256 > setAskFor
Definition: net.h:743
Definition: coins.h:73
void RelayTransaction(const CTransaction &tx)
Definition: net.cpp:2477
CActiveMasternode activeMasternode
bool IsTxLockCandidateTimedOut(const uint256 &txHash)
Definition: instantx.cpp:816
bool GetLockedOutPointTxHash(const COutPoint &outpoint, uint256 &hashRet)
Definition: instantx.cpp:530
int GetUTXOHeight(const COutPoint &outpoint)
Definition: validation.cpp:454
bool GetTxLockVote(const uint256 &hash, CTxLockVote &txLockVoteRet)
Definition: instantx.cpp:747
std::map< uint256, CTxLockVote > mapTxLockVotesOrphan
Definition: instantx.h:54
static const int SPORK_3_INSTANTSEND_BLOCK_FILTERING
Definition: spork.h:23
bool IsExpired(int nHeight) const
Definition: instantx.cpp:1091
void AcceptLockRequest(const CTxLockRequest &txLockRequest)
Definition: instantx.cpp:718
#define strprintf
Definition: tinyformat.h:1011
bool IsAllOutPointsReady() const
Definition: instantx.cpp:1167
static const int SPORK_5_INSTANTSEND_MAX_VALUE
Definition: spork.h:24
bool IsEnoughOrphanVotesForTxAndOutPoint(const uint256 &txHash, const COutPoint &outpoint)
Definition: instantx.cpp:440
uint64_t GetHash(const uint256 &salt) const
Definition: uint256.cpp:126
bool GetUTXOCoins(const COutPoint &outpoint, CCoins &coins)
Definition: validation.cpp:446
void UpdatedBlockTip(const CBlockIndex *pindex)
Definition: instantx.cpp:841
CCriticalSection cs_wallet
Definition: wallet.h:672
static const int SIGNATURES_REQUIRED
Definition: instantx.h:208
int nConfirmedHeight
Definition: instantx.h:231
static const int DEFAULT_INSTANTSEND_DEPTH
Definition: instantx.h:29
std::map< COutPoint, COutPointLock > mapOutPointLocks
Definition: instantx.h:243
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:55
static const CAmount COIN
Definition: amount.h:16
void Relay(const uint256 &txHash, CConnman &connman)
Definition: instantx.cpp:831
bool CreateTxLockCandidate(const CTxLockRequest &txLockRequest)
Definition: instantx.cpp:131
CCriticalSection cs_main
Definition: validation.cpp:62
CAmount nValue
Definition: transaction.h:136
std::map< uint256, CTxLockVote > mapTxLockVotes
Definition: instantx.h:53
std::map< COutPoint, CInPoint > mapNextTx
Definition: txmempool.h:441
Definition: net.h:108
static const int SIGNATURES_TOTAL
Definition: instantx.h:209
void CheckAndRemove()
Definition: instantx.cpp:631
void RelayInv(CInv &inv, const int minProtoVersion=MIN_PEER_PROTO_VERSION)
Definition: net.cpp:2528
CPubKey pubKeyMasternode
Definition: masternode.h:117
bool HasMasternodeVoted(const COutPoint &outpointMasternodeIn) const
Definition: instantx.cpp:1130
bool AlreadyHave(const uint256 &hash)
Definition: instantx.cpp:710
uint256 GetHash() const
Definition: instantx.cpp:1038
void AskForMN(CNode *pnode, const COutPoint &outpoint, CConnman &connman)
Ask (source) node for mnb.
uint256 GetHash() const
Definition: instantx.h:245
void Relay(CConnman &connman) const
Definition: instantx.cpp:1135
std::map< uint256, CTxLockRequest > mapLockRequestRejected
Definition: instantx.h:52
bool AddVote(const CTxLockVote &vote)
Definition: instantx.cpp:1160
bool IsFailed() const
Definition: instantx.cpp:1102
void ProcessOrphanTxLockVotes(CConnman &connman)
Definition: instantx.cpp:408
uint256 GetTxHash() const
Definition: instantx.h:184
COutPoint GetOutpoint() const
Definition: instantx.h:185
bool fEnableInstantSend
Definition: instantx.cpp:26
bool fLargeWorkForkFound
void Relay(CConnman &connman) const
Definition: instantx.cpp:1085
const char * TXLOCKVOTE
Definition: protocol.cpp:40
bool IsTimedOut() const
Definition: instantx.cpp:1203
bool fMasterNode
Definition: util.cpp:108
std::map< COutPoint, uint256 > mapLockedOutpoints
Definition: instantx.h:59
COutPoint outpoint
Definition: instantx.h:146
bool UpdatedTransaction(const uint256 &hashTx)
Definition: wallet.cpp:4168
int64_t CAmount
Definition: amount.h:14
int nInstantSendKeepLock
Definition: params.h:49
void RejectLockRequest(const CTxLockRequest &txLockRequest)
Definition: instantx.cpp:724
uint256 GetHash()
Definition: hash.h:254
#define AssertLockHeld(cs)
Definition: sync.h:96
bool IsUnspendable() const
Definition: script.h:634
bool fLiteMode
Definition: util.cpp:109
#define LOCK2(cs1, cs2)
Definition: sync.h:169
std::vector< CTxOut > vout
unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are d...
Definition: coins.h:80
std::map< COutPoint, CTxLockVote > mapMasternodeVotes
Definition: instantx.h:204
bool fLargeWorkInvalidChainFound
bool IsInstantSendReadyToLock(const uint256 &txHash)
Definition: instantx.cpp:758
CCriticalSection cs
Definition: txmempool.h:402
#define LogPrintf(...)
Definition: util.h:98
bool CheckFinalTx(const CTransaction &tx, int flags)
Definition: validation.cpp:213
int GetTransactionLockSignatures(const uint256 &txHash)
Definition: instantx.cpp:795
void Vote(CTxLockCandidate &txLockCandidate, CConnman &connman)
Definition: instantx.cpp:178
int nCachedBlockHeight
Definition: instantx.h:48
COutPoint prevout
Definition: transaction.h:61
CCriticalSection cs_instantsend
Definition: instantx.h:84
Definition: net.h:661
CTxLockRequest txLockRequest
Definition: instantx.h:242
static int LogPrint(const char *category, const char *format)
Definition: util.h:126
int GetConfirmations(const uint256 &nTXHash)
Definition: instantx.cpp:811
#define LOCK(cs)
Definition: sync.h:168
static const int INSTANTSEND_FAILED_TIMEOUT_SECONDS
Definition: instantx.h:38
bool GetMasternodeInfo(const COutPoint &outpoint, masternode_info_t &mnInfoRet)
std::string ToString()
Definition: instantx.cpp:912
int Height() const
Definition: chain.h:397
bool IsNormalPaymentScript() const
Definition: script.cpp:203
COutPoint GetMasternodeOutpoint() const
Definition: instantx.h:186
void ProcessMessage(CNode *pfrom, std::string &strCommand, CDataStream &vRecv, CConnman &connman)
Definition: instantx.cpp:43
CInstantSend instantsend
Definition: instantx.cpp:30
std::atomic< bool > fDIP0001ActiveAtTip
Definition: validation.cpp:89
CMainSignals & GetMainSignals()
std::map< COutPoint, int64_t > mapMasternodeOrphanVotes
Definition: instantx.h:62
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)
Definition: instantx.cpp:770
CChain chainActive
Definition: validation.cpp:65
std::string ToString() const
Definition: uint256.cpp:65
int64_t nTimeCreated
Definition: instantx.h:232
CScript scriptPubKey
Definition: transaction.h:137
bool IsValid(CNode *pnode, CConnman &connman) const
Definition: instantx.cpp:999
int64_t nTimeCreated
Definition: instantx.h:151
std::map< uint256, CTxLockCandidate > mapTxLockCandidates
Definition: instantx.h:56
int nInstantSendDepth
Definition: instantx.cpp:27
CSporkManager sporkManager
Definition: spork.cpp:14
const std::vector< CTxIn > vin
Definition: transaction.h:233
bool CheckSignature() const
Definition: instantx.cpp:1047
bool IsExpired(int nHeight) const
Definition: instantx.cpp:1197
CTxMemPool mempool
bool IsValid() const
Definition: instantx.cpp:922
std::string ToString() const
Definition: transaction.cpp:12
void Relay(CConnman &connman) const
Definition: instantx.cpp:1208
const CChainParams & Params()
static const int PROTOCOL_VERSION
Definition: version.h:13
const uint256 & GetHash() const
Definition: transaction.h:262
CAmount GetMinFee() const
Definition: instantx.cpp:984
std::map< COutPoint, std::set< uint256 > > mapVotedOutpoints
Definition: instantx.h:58
bool ProcessTxLockRequest(const CTxLockRequest &txLockRequest, CConnman &connman)
Definition: instantx.cpp:80
void runCommand(const std::string &strCommand)
Definition: util.cpp:866
CWallet * pwalletMain
std::string ToString() const
bool IsCoinBase() const
Definition: transaction.h:284
bool ProcessTxLockVote(CNode *pfrom, CTxLockVote &vote, CConnman &connman)
Definition: instantx.cpp:278
std::string GetHex() const
Definition: uint256.cpp:21
bool AddVote(const CTxLockVote &vote)
Definition: instantx.cpp:1111
std::vector< unsigned char > vchMasternodeSignature
Definition: instantx.h:148
Definition: protocol.h:314
const std::vector< CTxOut > vout
Definition: transaction.h:234
bool PoSeBan(const COutPoint &outpoint)
uint256 txHash
Definition: instantx.h:145
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)
Definition: instantx.cpp:730
static const int INSTANTSEND_LOCK_TIMEOUT_SECONDS
Definition: instantx.h:35
std::string GetArg(const std::string &strArg, const std::string &strDefault)
Definition: util.cpp:441
bool GetTxLockRequest(const uint256 &txHash, CTxLockRequest &txLockRequestRet)
Definition: instantx.cpp:736
static const int WARN_MANY_INPUTS
Definition: instantx.h:127
void AddOutPointLock(const COutPoint &outpoint)
Definition: instantx.cpp:1148
void MarkOutpointAsAttacked(const COutPoint &outpoint)
Definition: instantx.cpp:1153
bool IsSporkActive(int nSporkID)
Definition: spork.cpp:120
int64_t GetTime()
For unit testing.
Definition: utiltime.cpp:20
static const int MIN_INSTANTSEND_PROTO_VERSION
Definition: instantx.h:31
bool GetTransaction(const uint256 &hash, CTransaction &txOut, const Consensus::Params &consensusParams, uint256 &hashBlock, bool fAllowSlow)
bool IsEnoughOrphanVotesForTx(const CTxLockRequest &txLockRequest)
Definition: instantx.cpp:427
std::vector< CTxLockVote > GetVotes() const
Definition: instantx.cpp:1119
void SyncTransaction(const CTransaction &tx, const CBlock *pblock)
Definition: instantx.cpp:846
int GetMaxSignatures() const
Definition: instantx.cpp:990
int64_t GetSporkValue(int nSporkID)
Definition: spork.cpp:148
Definition: block.h:73
bool Sign()
Definition: instantx.cpp:1067
uint256 GetHash() const
Definition: block.cpp:13
std::map< uint256, CTxLockRequest > mapLockRequestAccepted
Definition: instantx.h:51
void LockTransactionInputs(const CTxLockCandidate &txLockCandidate)
Definition: instantx.cpp:511
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:113
std::string ToStringShort() const
Definition: transaction.cpp:17
static const int SPORK_2_INSTANTSEND_ENABLED
Definition: spork.h:22
bool IsMasternodeListSynced()
BlockMap mapBlockIndex
Definition: validation.cpp:64
std::atomic< int > nVersion
Definition: net.h:692
bool ResolveConflicts(const CTxLockCandidate &txLockCandidate)
Definition: instantx.cpp:539
bool IsTimedOut() const
Definition: instantx.cpp:1097
int nHeight
at which height this transaction was included in the active block chain
Definition: coins.h:83
void CreateEmptyTxLockCandidate(const uint256 &txHash)
Definition: instantx.cpp:169
bool HasMasternodeVoted(const COutPoint &outpointIn, const COutPoint &outpointMasternodeIn)
Definition: instantx.cpp:1179