Dash Core  0.12.2.1
P2P Digital Currency
privatesend-server.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 #include "privatesend-server.h"
5 
6 #include "activemasternode.h"
7 #include "consensus/validation.h"
8 #include "core_io.h"
9 #include "init.h"
10 #include "masternode-sync.h"
11 #include "masternodeman.h"
12 #include "txmempool.h"
13 #include "util.h"
14 #include "utilmoneystr.h"
15 
17 
18 void CPrivateSendServer::ProcessMessage(CNode* pfrom, std::string& strCommand, CDataStream& vRecv, CConnman& connman)
19 {
20  if(!fMasterNode) return;
21  if(fLiteMode) return; // ignore all Dash related functionality
22  if(!masternodeSync.IsBlockchainSynced()) return;
23 
24  if(strCommand == NetMsgType::DSACCEPT) {
25 
27  LogPrintf("DSACCEPT -- incompatible version! nVersion: %d\n", pfrom->nVersion);
28  PushStatus(pfrom, STATUS_REJECTED, ERR_VERSION, connman);
29  return;
30  }
31 
32  if(IsSessionReady()) {
33  // too many users in this session already, reject new ones
34  LogPrintf("DSACCEPT -- queue is already full!\n");
35  PushStatus(pfrom, STATUS_ACCEPTED, ERR_QUEUE_FULL, connman);
36  return;
37  }
38 
39  int nDenom;
40  CTransaction txCollateral;
41  vRecv >> nDenom >> txCollateral;
42 
43  LogPrint("privatesend", "DSACCEPT -- nDenom %d (%s) txCollateral %s", nDenom, CPrivateSend::GetDenominationsToString(nDenom), txCollateral.ToString());
44 
45  masternode_info_t mnInfo;
47  PushStatus(pfrom, STATUS_REJECTED, ERR_MN_LIST, connman);
48  return;
49  }
50 
51  if(vecSessionCollaterals.size() == 0 && mnInfo.nLastDsq != 0 &&
53  {
54  LogPrintf("DSACCEPT -- last dsq too recent, must wait: addr=%s\n", pfrom->addr.ToString());
55  PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman);
56  return;
57  }
58 
59  PoolMessage nMessageID = MSG_NOERR;
60 
61  bool fResult = nSessionID == 0 ? CreateNewSession(nDenom, txCollateral, nMessageID, connman)
62  : AddUserToExistingSession(nDenom, txCollateral, nMessageID);
63  if(fResult) {
64  LogPrintf("DSACCEPT -- is compatible, please submit!\n");
65  PushStatus(pfrom, STATUS_ACCEPTED, nMessageID, connman);
66  return;
67  } else {
68  LogPrintf("DSACCEPT -- not compatible with existing transactions!\n");
69  PushStatus(pfrom, STATUS_REJECTED, nMessageID, connman);
70  return;
71  }
72 
73  } else if(strCommand == NetMsgType::DSQUEUE) {
74  TRY_LOCK(cs_darksend, lockRecv);
75  if(!lockRecv) return;
76 
78  LogPrint("privatesend", "DSQUEUE -- incompatible version! nVersion: %d\n", pfrom->nVersion);
79  return;
80  }
81 
82  CDarksendQueue dsq;
83  vRecv >> dsq;
84 
85  // process every dsq only once
86  BOOST_FOREACH(CDarksendQueue q, vecDarksendQueue) {
87  if(q == dsq) {
88  // LogPrint("privatesend", "DSQUEUE -- %s seen\n", dsq.ToString());
89  return;
90  }
91  }
92 
93  LogPrint("privatesend", "DSQUEUE -- %s new\n", dsq.ToString());
94 
95  if(dsq.IsExpired()) return;
96 
97  masternode_info_t mnInfo;
98  if(!mnodeman.GetMasternodeInfo(dsq.vin.prevout, mnInfo)) return;
99 
100  if(!dsq.CheckSignature(mnInfo.pubKeyMasternode)) {
101  // we probably have outdated info
102  mnodeman.AskForMN(pfrom, dsq.vin.prevout, connman);
103  return;
104  }
105 
106  if(!dsq.fReady) {
107  BOOST_FOREACH(CDarksendQueue q, vecDarksendQueue) {
108  if(q.vin == dsq.vin) {
109  // no way same mn can send another "not yet ready" dsq this soon
110  LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending WAY too many dsq messages\n", mnInfo.addr.ToString());
111  return;
112  }
113  }
114 
116  LogPrint("privatesend", "DSQUEUE -- nLastDsq: %d threshold: %d nDsqCount: %d\n", mnInfo.nLastDsq, nThreshold, mnodeman.nDsqCount);
117  //don't allow a few nodes to dominate the queuing process
118  if(mnInfo.nLastDsq != 0 && nThreshold > mnodeman.nDsqCount) {
119  LogPrint("privatesend", "DSQUEUE -- Masternode %s is sending too many dsq messages\n", mnInfo.addr.ToString());
120  return;
121  }
122  mnodeman.AllowMixing(dsq.vin.prevout);
123 
124  LogPrint("privatesend", "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), mnInfo.addr.ToString());
125  vecDarksendQueue.push_back(dsq);
126  dsq.Relay(connman);
127  }
128 
129  } else if(strCommand == NetMsgType::DSVIN) {
130 
132  LogPrintf("DSVIN -- incompatible version! nVersion: %d\n", pfrom->nVersion);
133  PushStatus(pfrom, STATUS_REJECTED, ERR_VERSION, connman);
134  return;
135  }
136 
137  //do we have enough users in the current session?
138  if(!IsSessionReady()) {
139  LogPrintf("DSVIN -- session not complete!\n");
140  PushStatus(pfrom, STATUS_REJECTED, ERR_SESSION, connman);
141  return;
142  }
143 
144  CDarkSendEntry entry;
145  vRecv >> entry;
146 
147  LogPrint("privatesend", "DSVIN -- txCollateral %s", entry.txCollateral.ToString());
148 
149  if(entry.vecTxDSIn.size() > PRIVATESEND_ENTRY_MAX_SIZE) {
150  LogPrintf("DSVIN -- ERROR: too many inputs! %d/%d\n", entry.vecTxDSIn.size(), PRIVATESEND_ENTRY_MAX_SIZE);
151  PushStatus(pfrom, STATUS_REJECTED, ERR_MAXIMUM, connman);
152  return;
153  }
154 
155  if(entry.vecTxDSOut.size() > PRIVATESEND_ENTRY_MAX_SIZE) {
156  LogPrintf("DSVIN -- ERROR: too many outputs! %d/%d\n", entry.vecTxDSOut.size(), PRIVATESEND_ENTRY_MAX_SIZE);
157  PushStatus(pfrom, STATUS_REJECTED, ERR_MAXIMUM, connman);
158  return;
159  }
160 
161  //do we have the same denominations as the current session?
162  if(!IsOutputsCompatibleWithSessionDenom(entry.vecTxDSOut)) {
163  LogPrintf("DSVIN -- not compatible with existing transactions!\n");
164  PushStatus(pfrom, STATUS_REJECTED, ERR_EXISTING_TX, connman);
165  return;
166  }
167 
168  //check it like a transaction
169  {
170  CAmount nValueIn = 0;
171  CAmount nValueOut = 0;
172 
174 
175  BOOST_FOREACH(const CTxOut txout, entry.vecTxDSOut) {
176  nValueOut += txout.nValue;
177  tx.vout.push_back(txout);
178 
179  if(txout.scriptPubKey.size() != 25) {
180  LogPrintf("DSVIN -- non-standard pubkey detected! scriptPubKey=%s\n", ScriptToAsmStr(txout.scriptPubKey));
182  return;
183  }
184  if(!txout.scriptPubKey.IsNormalPaymentScript()) {
185  LogPrintf("DSVIN -- invalid script! scriptPubKey=%s\n", ScriptToAsmStr(txout.scriptPubKey));
187  return;
188  }
189  }
190 
191  BOOST_FOREACH(const CTxIn txin, entry.vecTxDSIn) {
192  tx.vin.push_back(txin);
193 
194  LogPrint("privatesend", "DSVIN -- txin=%s\n", txin.ToString());
195 
196  CCoins coins;
197  if(GetUTXOCoins(txin.prevout, coins)) {
198  nValueIn += coins.vout[txin.prevout.n].nValue;
199  } else {
200  LogPrintf("DSVIN -- missing input! tx=%s", tx.ToString());
201  PushStatus(pfrom, STATUS_REJECTED, ERR_MISSING_TX, connman);
202  return;
203  }
204  }
205 
206  // There should be no fee in mixing tx
207  CAmount nFee = nValueIn - nValueOut;
208  if(nFee != 0) {
209  LogPrintf("DSVIN -- there should be no fee in mixing tx! fees: %lld, tx=%s", nFee, tx.ToString());
210  PushStatus(pfrom, STATUS_REJECTED, ERR_FEES, connman);
211  return;
212  }
213 
214  {
215  LOCK(cs_main);
216  CValidationState validationState;
217  mempool.PrioritiseTransaction(tx.GetHash(), tx.GetHash().ToString(), 1000, 0.1*COIN);
218  if(!AcceptToMemoryPool(mempool, validationState, CTransaction(tx), false, NULL, false, true, true)) {
219  LogPrintf("DSVIN -- transaction not valid! tx=%s", tx.ToString());
220  PushStatus(pfrom, STATUS_REJECTED, ERR_INVALID_TX, connman);
221  return;
222  }
223  }
224  }
225 
226  PoolMessage nMessageID = MSG_NOERR;
227 
228  entry.addr = pfrom->addr;
229  if(AddEntry(entry, nMessageID)) {
230  PushStatus(pfrom, STATUS_ACCEPTED, nMessageID, connman);
231  CheckPool(connman);
232  RelayStatus(STATUS_ACCEPTED, connman);
233  } else {
234  PushStatus(pfrom, STATUS_REJECTED, nMessageID, connman);
235  SetNull();
236  }
237 
238  } else if(strCommand == NetMsgType::DSSIGNFINALTX) {
239 
241  LogPrintf("DSSIGNFINALTX -- incompatible version! nVersion: %d\n", pfrom->nVersion);
242  return;
243  }
244 
245  std::vector<CTxIn> vecTxIn;
246  vRecv >> vecTxIn;
247 
248  LogPrint("privatesend", "DSSIGNFINALTX -- vecTxIn.size() %s\n", vecTxIn.size());
249 
250  int nTxInIndex = 0;
251  int nTxInsCount = (int)vecTxIn.size();
252 
253  BOOST_FOREACH(const CTxIn txin, vecTxIn) {
254  nTxInIndex++;
255  if(!AddScriptSig(txin)) {
256  LogPrint("privatesend", "DSSIGNFINALTX -- AddScriptSig() failed at %d/%d, session: %d\n", nTxInIndex, nTxInsCount, nSessionID);
257  RelayStatus(STATUS_REJECTED, connman);
258  return;
259  }
260  LogPrint("privatesend", "DSSIGNFINALTX -- AddScriptSig() %d/%d success\n", nTxInIndex, nTxInsCount);
261  }
262  // all is good
263  CheckPool(connman);
264  }
265 }
266 
268 {
269  // MN side
270  vecSessionCollaterals.clear();
271 
273 }
274 
275 //
276 // Check the mixing progress and send client updates if a Masternode
277 //
279 {
280  if(fMasterNode) {
281  LogPrint("privatesend", "CPrivateSendServer::CheckPool -- entries count %lu\n", GetEntriesCount());
282 
283  // If entries are full, create finalized transaction
285  LogPrint("privatesend", "CPrivateSendServer::CheckPool -- FINALIZE TRANSACTIONS\n");
286  CreateFinalTransaction(connman);
287  return;
288  }
289 
290  // If we have all of the signatures, try to compile the transaction
292  LogPrint("privatesend", "CPrivateSendServer::CheckPool -- SIGNING\n");
293  CommitFinalTransaction(connman);
294  return;
295  }
296  }
297 
298  // reset if we're here for 10 seconds
300  LogPrint("privatesend", "CPrivateSendServer::CheckPool -- timeout, RESETTING\n");
301  SetNull();
302  }
303 }
304 
306 {
307  LogPrint("privatesend", "CPrivateSendServer::CreateFinalTransaction -- FINALIZE TRANSACTIONS\n");
308 
309  CMutableTransaction txNew;
310 
311  // make our new transaction
312  for(int i = 0; i < GetEntriesCount(); i++) {
313  BOOST_FOREACH(const CTxDSOut& txdsout, vecEntries[i].vecTxDSOut)
314  txNew.vout.push_back(txdsout);
315 
316  BOOST_FOREACH(const CTxDSIn& txdsin, vecEntries[i].vecTxDSIn)
317  txNew.vin.push_back(txdsin);
318  }
319 
320  sort(txNew.vin.begin(), txNew.vin.end(), CompareInputBIP69());
321  sort(txNew.vout.begin(), txNew.vout.end(), CompareOutputBIP69());
322 
323  finalMutableTransaction = txNew;
324  LogPrint("privatesend", "CPrivateSendServer::CreateFinalTransaction -- finalMutableTransaction=%s", txNew.ToString());
325 
326  // request signatures from clients
329 }
330 
332 {
333  if(!fMasterNode) return; // check and relay final tx only on masternode
334 
336  uint256 hashTx = finalTransaction.GetHash();
337 
338  LogPrint("privatesend", "CPrivateSendServer::CommitFinalTransaction -- finalTransaction=%s", finalTransaction.ToString());
339 
340  {
341  // See if the transaction is valid
342  TRY_LOCK(cs_main, lockMain);
343  CValidationState validationState;
344  mempool.PrioritiseTransaction(hashTx, hashTx.ToString(), 1000, 0.1*COIN);
345  if(!lockMain || !AcceptToMemoryPool(mempool, validationState, finalTransaction, false, NULL, false, true, true))
346  {
347  LogPrintf("CPrivateSendServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n");
348  SetNull();
349  // not much we can do in this case, just notify clients
351  return;
352  }
353  }
354 
355  LogPrintf("CPrivateSendServer::CommitFinalTransaction -- CREATING DSTX\n");
356 
357  // create and sign masternode dstx transaction
358  if(!CPrivateSend::GetDSTX(hashTx)) {
359  CDarksendBroadcastTx dstxNew(finalTransaction, activeMasternode.outpoint, GetAdjustedTime());
360  dstxNew.Sign();
361  CPrivateSend::AddDSTX(dstxNew);
362  }
363 
364  LogPrintf("CPrivateSendServer::CommitFinalTransaction -- TRANSMITTING DSTX\n");
365 
366  CInv inv(MSG_DSTX, hashTx);
367  connman.RelayInv(inv);
368 
369  // Tell the clients it was successful
371 
372  // Randomly charge clients
373  ChargeRandomFees(connman);
374 
375  // Reset
376  LogPrint("privatesend", "CPrivateSendServer::CommitFinalTransaction -- COMPLETED -- RESETTING\n");
377  SetNull();
378 }
379 
380 //
381 // Charge clients a fee if they're abusive
382 //
383 // Why bother? PrivateSend uses collateral to ensure abuse to the process is kept to a minimum.
384 // The submission and signing stages are completely separate. In the cases where
385 // a client submits a transaction then refused to sign, there must be a cost. Otherwise they
386 // would be able to do this over and over again and bring the mixing to a hault.
387 //
388 // How does this work? Messages to Masternodes come in via NetMsgType::DSVIN, these require a valid collateral
389 // transaction for the client to be able to enter the pool. This transaction is kept by the Masternode
390 // until the transaction is either complete or fails.
391 //
393 {
394  if(!fMasterNode) return;
395 
396  //we don't need to charge collateral for every offence.
397  if(GetRandInt(100) > 33) return;
398 
399  std::vector<CTransaction> vecOffendersCollaterals;
400 
402  BOOST_FOREACH(const CTransaction& txCollateral, vecSessionCollaterals) {
403  bool fFound = false;
404  BOOST_FOREACH(const CDarkSendEntry& entry, vecEntries)
405  if(entry.txCollateral == txCollateral)
406  fFound = true;
407 
408  // This queue entry didn't send us the promised transaction
409  if(!fFound) {
410  LogPrintf("CPrivateSendServer::ChargeFees -- found uncooperative node (didn't send transaction), found offence\n");
411  vecOffendersCollaterals.push_back(txCollateral);
412  }
413  }
414  }
415 
416  if(nState == POOL_STATE_SIGNING) {
417  // who didn't sign?
418  BOOST_FOREACH(const CDarkSendEntry entry, vecEntries) {
419  BOOST_FOREACH(const CTxDSIn txdsin, entry.vecTxDSIn) {
420  if(!txdsin.fHasSig) {
421  LogPrintf("CPrivateSendServer::ChargeFees -- found uncooperative node (didn't sign), found offence\n");
422  vecOffendersCollaterals.push_back(entry.txCollateral);
423  }
424  }
425  }
426  }
427 
428  // no offences found
429  if(vecOffendersCollaterals.empty()) return;
430 
431  //mostly offending? Charge sometimes
432  if((int)vecOffendersCollaterals.size() >= Params().PoolMaxTransactions() - 1 && GetRandInt(100) > 33) return;
433 
434  //everyone is an offender? That's not right
435  if((int)vecOffendersCollaterals.size() >= Params().PoolMaxTransactions()) return;
436 
437  //charge one of the offenders randomly
438  std::random_shuffle(vecOffendersCollaterals.begin(), vecOffendersCollaterals.end());
439 
441  LogPrintf("CPrivateSendServer::ChargeFees -- found uncooperative node (didn't %s transaction), charging fees: %s\n",
442  (nState == POOL_STATE_SIGNING) ? "sign" : "send", vecOffendersCollaterals[0].ToString());
443 
444  LOCK(cs_main);
445 
446  CValidationState state;
447  bool fMissingInputs;
448  if(!AcceptToMemoryPool(mempool, state, vecOffendersCollaterals[0], false, &fMissingInputs, false, true)) {
449  // should never really happen
450  LogPrintf("CPrivateSendServer::ChargeFees -- ERROR: AcceptToMemoryPool failed!\n");
451  } else {
452  connman.RelayTransaction(vecOffendersCollaterals[0]);
453  }
454  }
455 }
456 
457 /*
458  Charge the collateral randomly.
459  Mixing is completely free, to pay miners we randomly pay the collateral of users.
460 
461  Collateral Fee Charges:
462 
463  Being that mixing has "no fees" we need to have some kind of cost associated
464  with using it to stop abuse. Otherwise it could serve as an attack vector and
465  allow endless transaction that would bloat Dash and make it unusable. To
466  stop these kinds of attacks 1 in 10 successful transactions are charged. This
467  adds up to a cost of 0.001DRK per transaction on average.
468 */
470 {
471  if(!fMasterNode) return;
472 
473  LOCK(cs_main);
474 
475  BOOST_FOREACH(const CTransaction& txCollateral, vecSessionCollaterals) {
476 
477  if(GetRandInt(100) > 10) return;
478 
479  LogPrintf("CPrivateSendServer::ChargeRandomFees -- charging random fees, txCollateral=%s", txCollateral.ToString());
480 
481  CValidationState state;
482  bool fMissingInputs;
483  if(!AcceptToMemoryPool(mempool, state, txCollateral, false, &fMissingInputs, false, true)) {
484  // should never really happen
485  LogPrintf("CPrivateSendServer::ChargeRandomFees -- ERROR: AcceptToMemoryPool failed!\n");
486  } else {
487  connman.RelayTransaction(txCollateral);
488  }
489  }
490 }
491 
492 //
493 // Check for various timeouts (queue objects, mixing, etc)
494 //
496 {
497  {
498  TRY_LOCK(cs_darksend, lockDS);
499  if(!lockDS) return; // it's ok to fail here, we run this quite frequently
500 
501  // check mixing queue objects for timeouts
502  std::vector<CDarksendQueue>::iterator it = vecDarksendQueue.begin();
503  while(it != vecDarksendQueue.end()) {
504  if((*it).IsExpired()) {
505  LogPrint("privatesend", "CPrivateSendServer::CheckTimeout -- Removing expired queue (%s)\n", (*it).ToString());
506  it = vecDarksendQueue.erase(it);
507  } else ++it;
508  }
509  }
510 
511  if(!fMasterNode) return;
512 
513  int nLagTime = fMasterNode ? 0 : 10000; // if we're the client, give the server a few extra seconds before resetting.
515  bool fTimeout = GetTimeMillis() - nTimeLastSuccessfulStep >= nTimeout*1000 + nLagTime;
516 
517  if(nState != POOL_STATE_IDLE && fTimeout) {
518  LogPrint("privatesend", "CPrivateSendServer::CheckTimeout -- %s timed out (%ds) -- restting\n",
519  (nState == POOL_STATE_SIGNING) ? "Signing" : "Session", nTimeout);
520  ChargeFees(connman);
521  SetNull();
523  }
524 }
525 
526 /*
527  Check to see if we're ready for submissions from clients
528  After receiving multiple dsa messages, the queue will switch to "accepting entries"
529  which is the active state right before merging the transaction
530 */
532 {
533  if(!fMasterNode) return;
534 
537 
539  LogPrint("privatesend", "CPrivateSendServer::CheckForCompleteQueue -- queue is ready, signing and relaying (%s)\n", dsq.ToString());
540  dsq.Sign();
541  dsq.Relay(connman);
542  }
543 }
544 
545 // Check to make sure a given input matches an input in the pool and its scriptSig is valid
547 {
548  CMutableTransaction txNew;
549  txNew.vin.clear();
550  txNew.vout.clear();
551 
552  int i = 0;
553  int nTxInIndex = -1;
554  CScript sigPubKey = CScript();
555 
556  BOOST_FOREACH(CDarkSendEntry& entry, vecEntries) {
557 
558  BOOST_FOREACH(const CTxDSOut& txdsout, entry.vecTxDSOut)
559  txNew.vout.push_back(txdsout);
560 
561  BOOST_FOREACH(const CTxDSIn& txdsin, entry.vecTxDSIn) {
562  txNew.vin.push_back(txdsin);
563 
564  if(txdsin.prevout == txin.prevout) {
565  nTxInIndex = i;
566  sigPubKey = txdsin.prevPubKey;
567  }
568  i++;
569  }
570  }
571 
572  if(nTxInIndex >= 0) { //might have to do this one input at a time?
573  txNew.vin[nTxInIndex].scriptSig = txin.scriptSig;
574  LogPrint("privatesend", "CPrivateSendServer::IsInputScriptSigValid -- verifying scriptSig %s\n", ScriptToAsmStr(txin.scriptSig).substr(0,24));
575  if(!VerifyScript(txNew.vin[nTxInIndex].scriptSig, sigPubKey, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, MutableTransactionSignatureChecker(&txNew, nTxInIndex))) {
576  LogPrint("privatesend", "CPrivateSendServer::IsInputScriptSigValid -- VerifyScript() failed on input %d\n", nTxInIndex);
577  return false;
578  }
579  } else {
580  LogPrint("privatesend", "CPrivateSendServer::IsInputScriptSigValid -- Failed to find matching input in pool, %s\n", txin.ToString());
581  return false;
582  }
583 
584  LogPrint("privatesend", "CPrivateSendServer::IsInputScriptSigValid -- Successfully validated input and scriptSig\n");
585  return true;
586 }
587 
588 //
589 // Add a clients transaction to the pool
590 //
591 bool CPrivateSendServer::AddEntry(const CDarkSendEntry& entryNew, PoolMessage& nMessageIDRet)
592 {
593  if(!fMasterNode) return false;
594 
595  BOOST_FOREACH(CTxIn txin, entryNew.vecTxDSIn) {
596  if(txin.prevout.IsNull()) {
597  LogPrint("privatesend", "CPrivateSendServer::AddEntry -- input not valid!\n");
598  nMessageIDRet = ERR_INVALID_INPUT;
599  return false;
600  }
601  }
602 
604  LogPrint("privatesend", "CPrivateSendServer::AddEntry -- collateral not valid!\n");
605  nMessageIDRet = ERR_INVALID_COLLATERAL;
606  return false;
607  }
608 
610  LogPrint("privatesend", "CPrivateSendServer::AddEntry -- entries is full!\n");
611  nMessageIDRet = ERR_ENTRIES_FULL;
612  return false;
613  }
614 
615  BOOST_FOREACH(CTxIn txin, entryNew.vecTxDSIn) {
616  LogPrint("privatesend", "looking for txin -- %s\n", txin.ToString());
617  BOOST_FOREACH(const CDarkSendEntry& entry, vecEntries) {
618  BOOST_FOREACH(const CTxDSIn& txdsin, entry.vecTxDSIn) {
619  if(txdsin.prevout == txin.prevout) {
620  LogPrint("privatesend", "CPrivateSendServer::AddEntry -- found in txin\n");
621  nMessageIDRet = ERR_ALREADY_HAVE;
622  return false;
623  }
624  }
625  }
626  }
627 
628  vecEntries.push_back(entryNew);
629 
630  LogPrint("privatesend", "CPrivateSendServer::AddEntry -- adding entry\n");
631  nMessageIDRet = MSG_ENTRIES_ADDED;
633 
634  return true;
635 }
636 
638 {
639  LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0,24));
640 
641  BOOST_FOREACH(const CDarkSendEntry& entry, vecEntries) {
642  BOOST_FOREACH(const CTxDSIn& txdsin, entry.vecTxDSIn) {
643  if(txdsin.scriptSig == txinNew.scriptSig) {
644  LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- already exists\n");
645  return false;
646  }
647  }
648  }
649 
650  if(!IsInputScriptSigValid(txinNew)) {
651  LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- Invalid scriptSig\n");
652  return false;
653  }
654 
655  LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- scriptSig=%s new\n", ScriptToAsmStr(txinNew.scriptSig).substr(0,24));
656 
657  BOOST_FOREACH(CTxIn& txin, finalMutableTransaction.vin) {
658  if(txinNew.prevout == txin.prevout && txin.nSequence == txinNew.nSequence) {
659  txin.scriptSig = txinNew.scriptSig;
660  txin.prevPubKey = txinNew.prevPubKey;
661  LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- adding to finalMutableTransaction, scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0,24));
662  }
663  }
664  for(int i = 0; i < GetEntriesCount(); i++) {
665  if(vecEntries[i].AddScriptSig(txinNew)) {
666  LogPrint("privatesend", "CPrivateSendServer::AddScriptSig -- adding to entries, scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0,24));
667  return true;
668  }
669  }
670 
671  LogPrintf("CPrivateSendServer::AddScriptSig -- Couldn't set sig!\n" );
672  return false;
673 }
674 
675 // Check to make sure everything is signed
677 {
678  BOOST_FOREACH(const CDarkSendEntry& entry, vecEntries)
679  BOOST_FOREACH(const CTxDSIn& txdsin, entry.vecTxDSIn)
680  if(!txdsin.fHasSig) return false;
681 
682  return true;
683 }
684 
685 bool CPrivateSendServer::IsOutputsCompatibleWithSessionDenom(const std::vector<CTxDSOut>& vecTxDSOut)
686 {
687  if(CPrivateSend::GetDenominations(vecTxDSOut) == 0) return false;
688 
689  BOOST_FOREACH(const CDarkSendEntry entry, vecEntries) {
690  LogPrintf("CPrivateSendServer::IsOutputsCompatibleWithSessionDenom -- vecTxDSOut denom %d, entry.vecTxDSOut denom %d\n",
692  if(CPrivateSend::GetDenominations(vecTxDSOut) != CPrivateSend::GetDenominations(entry.vecTxDSOut)) return false;
693  }
694 
695  return true;
696 }
697 
699 {
700  if(!fMasterNode) return false;
701 
702  // is denom even smth legit?
703  std::vector<int> vecBits;
704  if(!CPrivateSend::GetDenominationsBits(nDenom, vecBits)) {
705  LogPrint("privatesend", "CPrivateSendServer::IsAcceptableDenomAndCollateral -- denom not valid!\n");
706  nMessageIDRet = ERR_DENOM;
707  return false;
708  }
709 
710  // check collateral
711  if(!fUnitTest && !CPrivateSend::IsCollateralValid(txCollateral)) {
712  LogPrint("privatesend", "CPrivateSendServer::IsAcceptableDenomAndCollateral -- collateral not valid!\n");
713  nMessageIDRet = ERR_INVALID_COLLATERAL;
714  return false;
715  }
716 
717  return true;
718 }
719 
720 bool CPrivateSendServer::CreateNewSession(int nDenom, CTransaction txCollateral, PoolMessage& nMessageIDRet, CConnman& connman)
721 {
722  if(!fMasterNode || nSessionID != 0) return false;
723 
724  // new session can only be started in idle mode
725  if(nState != POOL_STATE_IDLE) {
726  nMessageIDRet = ERR_MODE;
727  LogPrintf("CPrivateSendServer::CreateNewSession -- incompatible mode: nState=%d\n", nState);
728  return false;
729  }
730 
731  if(!IsAcceptableDenomAndCollateral(nDenom, txCollateral, nMessageIDRet)) {
732  return false;
733  }
734 
735  // start new session
736  nMessageIDRet = MSG_NOERR;
737  nSessionID = GetRandInt(999999)+1;
738  nSessionDenom = nDenom;
739 
742 
743  if(!fUnitTest) {
744  //broadcast that I'm accepting entries, only if it's the first entry through
746  LogPrint("privatesend", "CPrivateSendServer::CreateNewSession -- signing and relaying new queue: %s\n", dsq.ToString());
747  dsq.Sign();
748  dsq.Relay(connman);
749  vecDarksendQueue.push_back(dsq);
750  }
751 
752  vecSessionCollaterals.push_back(txCollateral);
753  LogPrintf("CPrivateSendServer::CreateNewSession -- new session created, nSessionID: %d nSessionDenom: %d (%s) vecSessionCollaterals.size(): %d\n",
755 
756  return true;
757 }
758 
759 bool CPrivateSendServer::AddUserToExistingSession(int nDenom, CTransaction txCollateral, PoolMessage& nMessageIDRet)
760 {
761  if(!fMasterNode || nSessionID == 0 || IsSessionReady()) return false;
762 
763  if(!IsAcceptableDenomAndCollateral(nDenom, txCollateral, nMessageIDRet)) {
764  return false;
765  }
766 
767  // we only add new users to an existing session when we are in queue mode
768  if(nState != POOL_STATE_QUEUE) {
769  nMessageIDRet = ERR_MODE;
770  LogPrintf("CPrivateSendServer::AddUserToExistingSession -- incompatible mode: nState=%d\n", nState);
771  return false;
772  }
773 
774  if(nDenom != nSessionDenom) {
775  LogPrintf("CPrivateSendServer::AddUserToExistingSession -- incompatible denom %d (%s) != nSessionDenom %d (%s)\n",
777  nMessageIDRet = ERR_DENOM;
778  return false;
779  }
780 
781  // count new user as accepted to an existing session
782 
783  nMessageIDRet = MSG_NOERR;
785  vecSessionCollaterals.push_back(txCollateral);
786 
787  LogPrintf("CPrivateSendServer::AddUserToExistingSession -- new user accepted, nSessionID: %d nSessionDenom: %d (%s) vecSessionCollaterals.size(): %d\n",
789 
790  return true;
791 }
792 
794 {
795  LogPrint("privatesend", "CPrivateSendServer::%s -- nSessionID: %d nSessionDenom: %d (%s)\n",
797 
798  // final mixing tx with empty signatures should be relayed to mixing participants only
799  for (const auto entry : vecEntries) {
800  bool fOk = connman.ForNode(entry.addr, [&txFinal, &connman, this](CNode* pnode) {
801  connman.PushMessage(pnode, NetMsgType::DSFINALTX, nSessionID, txFinal);
802  return true;
803  });
804  if(!fOk) {
805  // no such node? maybe this client disconnected or our own connection went down
806  RelayStatus(STATUS_REJECTED, connman);
807  break;
808  }
809  }
810 }
811 
812 void CPrivateSendServer::PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, CConnman& connman)
813 {
814  if(!pnode) return;
815  connman.PushMessage(pnode, NetMsgType::DSSTATUSUPDATE, nSessionID, (int)nState, (int)vecEntries.size(), (int)nStatusUpdate, (int)nMessageID);
816 }
817 
818 void CPrivateSendServer::RelayStatus(PoolStatusUpdate nStatusUpdate, CConnman& connman, PoolMessage nMessageID)
819 {
820  unsigned int nDisconnected{};
821  // status updates should be relayed to mixing participants only
822  for (const auto entry : vecEntries) {
823  // make sure everyone is still connected
824  bool fOk = connman.ForNode(entry.addr, [&nStatusUpdate, &nMessageID, &connman, this](CNode* pnode) {
825  PushStatus(pnode, nStatusUpdate, nMessageID, connman);
826  return true;
827  });
828  if(!fOk) {
829  // no such node? maybe this client disconnected or our own connection went down
830  ++nDisconnected;
831  }
832  }
833  if (nDisconnected == 0) return; // all is clear
834 
835  // smth went wrong
836  LogPrintf("CPrivateSendServer::%s -- can't continue, %llu client(s) disconnected, nSessionID: %d nSessionDenom: %d (%s)\n",
838 
839  // notify everyone else that this session should be terminated
840  for (const auto entry : vecEntries) {
841  connman.ForNode(entry.addr, [&connman, this](CNode* pnode) {
842  PushStatus(pnode, STATUS_REJECTED, MSG_NOERR, connman);
843  return true;
844  });
845  }
846 
847  if(nDisconnected == vecEntries.size()) {
848  // all clients disconnected, there is probably some issues with our own connection
849  // do not charge any fees, just reset the pool
850  SetNull();
851  }
852 }
853 
855 {
856  LogPrint("privatesend", "CPrivateSendServer::%s -- nSessionID: %d nSessionDenom: %d (%s)\n",
858 
859  // final mixing tx with empty signatures should be relayed to mixing participants only
860  for (const auto entry : vecEntries) {
861  bool fOk = connman.ForNode(entry.addr, [&nMessageID, &connman, this](CNode* pnode) {
862  connman.PushMessage(pnode, NetMsgType::DSCOMPLETE, nSessionID, (int)nMessageID);
863  return true;
864  });
865  if(!fOk) {
866  // no such node? maybe client disconnected or our own connection went down
867  RelayStatus(STATUS_REJECTED, connman);
868  break;
869  }
870  }
871 }
872 
874 {
875  if(fMasterNode && (nStateNew == POOL_STATE_ERROR || nStateNew == POOL_STATE_SUCCESS)) {
876  LogPrint("privatesend", "CPrivateSendServer::SetState -- Can't set state to ERROR or SUCCESS as a Masternode. \n");
877  return;
878  }
879 
880  LogPrintf("CPrivateSendServer::SetState -- nState: %d, nStateNew: %d\n", nState, nStateNew);
881  nState = nStateNew;
882 }
883 
884 //TODO: Rename/move to core
886 {
887  if(fLiteMode) return; // disable all Dash specific functionality
888 
889  static bool fOneThread;
890  if(fOneThread) return;
891  fOneThread = true;
892 
893  // Make this thread recognisable as the PrivateSend thread
894  RenameThread("dash-ps-server");
895 
896  unsigned int nTick = 0;
897 
898  while (true)
899  {
900  MilliSleep(1000);
901 
903  nTick++;
906  }
907  }
908 }
std::vector< CTransaction > vecSessionCollaterals
uint32_t n
Definition: transaction.h:19
bool IsNull() const
Definition: transaction.h:33
int64_t nDsqCount
Definition: masternodeman.h:91
CMasternodeMan mnodeman
CMasternodeSync masternodeSync
CPrivateSendServer privateSendServer
const char * DSACCEPT
Definition: protocol.cpp:54
Definition: coins.h:73
void RelayTransaction(const CTransaction &tx)
Definition: net.cpp:2477
PoolState nState
Definition: privatesend.h:287
void MilliSleep(int64_t n)
Definition: utiltime.cpp:63
CActiveMasternode activeMasternode
int GetRandInt(int nMax)
Definition: random.cpp:109
#define TRY_LOCK(cs, name)
Definition: sync.h:170
void CommitFinalTransaction(CConnman &connman)
bool fHasSig
Definition: privatesend.h:80
uint32_t nSequence
Definition: transaction.h:63
const char * DSQUEUE
Definition: protocol.cpp:61
bool ShutdownRequested()
Definition: init.cpp:168
bool GetUTXOCoins(const COutPoint &outpoint, CCoins &coins)
Definition: validation.cpp:446
static const CAmount COIN
Definition: amount.h:16
bool AddEntry(const CDarkSendEntry &entryNew, PoolMessage &nMessageIDRet)
Add a clients entry to the pool.
static std::string GetDenominationsToString(int nDenom)
CCriticalSection cs_main
Definition: validation.cpp:62
int PoolMaxTransactions() const
Definition: chainparams.h:81
CAmount nValue
Definition: transaction.h:136
CAddress addr
Definition: net.h:688
Definition: net.h:108
bool ForNode(NodeId id, std::function< bool(const CNode *pnode)> cond, std::function< bool(CNode *pnode)> func)
Definition: net.cpp:2879
std::string ToString() const
Definition: transaction.cpp:76
bool IsSessionReady()
Do we have enough users to take entries?
std::vector< CTxIn > vin
Definition: transaction.h:306
bool AcceptToMemoryPool(CTxMemPool &pool, CValidationState &state, const CTransaction &tx, bool fLimitFree, bool *pfMissingInputs, bool fOverrideMempoolLimit, bool fRejectAbsurdFee, bool fDryRun)
void RelayInv(CInv &inv, const int minProtoVersion=MIN_PEER_PROTO_VERSION)
Definition: net.cpp:2528
CPubKey pubKeyMasternode
Definition: masternode.h:117
static const int PRIVATESEND_QUEUE_TIMEOUT
Definition: privatesend.h:21
void AskForMN(CNode *pnode, const COutPoint &outpoint, CConnman &connman)
Ask (source) node for mnb.
std::string ToString(bool fUseGetnameinfo=true) const
Definition: netaddress.cpp:568
void RenameThread(const char *name)
Definition: util.cpp:873
PoolMessage
Definition: privatesend.h:30
static int GetDenominations(const std::vector< CTxOut > &vecTxOut, bool fSingleRandomDenom=false)
Get the denominations for a list of outputs (returns a bitshifted integer)
static void AddDSTX(const CDarksendBroadcastTx &dstx)
std::vector< CTxDSIn > vecTxDSIn
Definition: privatesend.h:118
void CreateFinalTransaction(CConnman &connman)
bool fMasterNode
Definition: util.cpp:108
CScript scriptSig
Definition: transaction.h:62
int64_t CAmount
Definition: amount.h:14
bool IsOutputsCompatibleWithSessionDenom(const std::vector< CTxDSOut > &vecTxDSOut)
Are these outputs compatible with other client in the pool?
bool fLiteMode
Definition: util.cpp:109
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
CCriticalSection cs_darksend
#define LogPrintf(...)
Definition: util.h:98
CTransaction txCollateral
Definition: privatesend.h:120
std::string ToString()
Definition: privatesend.h:205
static const CAmount PRIVATESEND_ENTRY_MAX_SIZE
Definition: privatesend.h:27
std::string ScriptToAsmStr(const CScript &script, const bool fAttemptSighashDecode=false)
Definition: core_write.cpp:75
void CheckForCompleteQueue(CConnman &connman)
COutPoint prevout
Definition: transaction.h:61
Definition: net.h:661
static int LogPrint(const char *category, const char *format)
Definition: util.h:126
#define LOCK(cs)
Definition: sync.h:168
std::string ToString() const
Definition: transaction.cpp:36
bool AddScriptSig(const CTxIn &txin)
Add signature to a txin.
bool Relay(CConnman &connman)
Definition: privatesend.cpp:75
bool GetMasternodeInfo(const COutPoint &outpoint, masternode_info_t &mnInfoRet)
void SetState(PoolState nStateNew)
bool IsNormalPaymentScript() const
Definition: script.cpp:203
int64_t nTimeLastSuccessfulStep
Definition: privatesend.h:288
bool AddUserToExistingSession(int nDenom, CTransaction txCollateral, PoolMessage &nMessageIDRet)
std::string ToString() const
Definition: uint256.cpp:65
static bool GetDenominationsBits(int nDenom, std::vector< int > &vecBitsRet)
CMutableTransaction finalMutableTransaction
Definition: privatesend.h:292
void CheckPool(CConnman &connman)
Check for process.
void CheckTimeout(CConnman &connman)
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, unsigned int flags, const BaseSignatureChecker &checker, ScriptError *serror)
CScript scriptPubKey
Definition: transaction.h:137
static const int PRIVATESEND_SIGNING_TIMEOUT
Definition: privatesend.h:22
std::vector< CTxOut > vout
Definition: transaction.h:307
const char * DSSIGNFINALTX
Definition: protocol.cpp:57
bool IsInputScriptSigValid(const CTxIn &txin)
Check to make sure a given input matches an input in the pool and its scriptSig is valid...
std::vector< CDarkSendEntry > vecEntries
Definition: privatesend.h:285
PoolStatusUpdate
Definition: privatesend.h:70
CTxMemPool mempool
int CountEnabled(int nProtocolVersion=-1)
bool CreateNewSession(int nDenom, CTransaction txCollateral, PoolMessage &nMessageIDRet, CConnman &connman)
uint256 GetHash() const
Definition: transaction.cpp:71
int GetEntriesCount() const
Definition: privatesend.h:305
const CChainParams & Params()
bool IsAcceptableDenomAndCollateral(int nDenom, CTransaction txCollateral, PoolMessage &nMessageIDRet)
Is this nDenom and txCollateral acceptable?
bool AllowMixing(const COutPoint &outpoint)
int64_t GetTimeMillis()
Definition: utiltime.cpp:34
const uint256 & GetHash() const
Definition: transaction.h:262
static int GetMaxPoolTransactions()
Get the maximum number of transactions for the pool.
Definition: privatesend.h:343
PoolState
Definition: privatesend.h:58
void PushStatus(CNode *pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, CConnman &connman)
int64_t GetAdjustedTime()
Definition: timedata.cpp:33
bool IsBlockchainSynced()
std::string ToString() const
static const int MIN_PRIVATESEND_PEER_PROTO_VERSION
minimum peer version accepted by mixing pool
Definition: privatesend.h:25
Definition: protocol.h:314
bool IsSignaturesComplete()
Check that all inputs are signed. (Are all inputs signed?)
static bool IsCollateralValid(const CTransaction &txCollateral)
If the collateral is valid given by a client.
void ProcessMessage(CNode *pfrom, std::string &strCommand, CDataStream &vRecv, CConnman &connman)
size_type size() const
Definition: prevector.h:262
void RelayCompletedTransaction(PoolMessage nMessageID, CConnman &connman)
void PrioritiseTransaction(const uint256 hash, const std::string strHash, double dPriorityDelta, const CAmount &nFeeDelta)
Definition: txmempool.cpp:934
void ChargeRandomFees(CConnman &connman)
Rarely charge fees to pay miners.
const char * DSVIN
Definition: protocol.cpp:55
void RelayStatus(PoolStatusUpdate nStatusUpdate, CConnman &connman, PoolMessage nMessageID=MSG_NOERR)
const char * DSSTATUSUPDATE
Definition: protocol.cpp:59
void ThreadCheckPrivateSendServer(CConnman &connman)
void ChargeFees(CConnman &connman)
Charge fees to bad actors (Charge clients a fee if they&#39;re abusive)
static CDarksendBroadcastTx GetDSTX(const uint256 &hash)
void PushMessage(CNode *pnode, const std::string &sCommand, Args &&... args)
Definition: net.h:199
std::atomic< int > nVersion
Definition: net.h:692
std::vector< CTxDSOut > vecTxDSOut
Definition: privatesend.h:119
CScript prevPubKey
Definition: transaction.h:64
void RelayFinalTransaction(const CTransaction &txFinal, CConnman &connman)
Relay mixing Messages.
std::vector< CDarksendQueue > vecDarksendQueue
Definition: privatesend.h:283