Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

privatesend-server.cpp
Go to the documentation of this file.
1 // Copyright (c) 2014-2020 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 
6 
8 #include <consensus/validation.h>
9 #include <core_io.h>
10 #include <init.h>
13 #include <net_processing.h>
14 #include <netmessagemaker.h>
15 #include <script/interpreter.h>
16 #include <txmempool.h>
17 #include <util.h>
18 #include <utilmoneystr.h>
19 #include <validation.h>
20 
22 
23 #include <univalue.h>
24 
26 
27 void CPrivateSendServer::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
28 {
29  if (!fMasternodeMode) return;
30  if (!masternodeSync.IsBlockchainSynced()) return;
31 
32  if (strCommand == NetMsgType::DSACCEPT) {
34  LogPrint(BCLog::PRIVATESEND, "DSACCEPT -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
35  if (g_enable_bip61) {
36  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
38  "Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION)));
39  }
40  PushStatus(pfrom, STATUS_REJECTED, ERR_VERSION, connman);
41  return;
42  }
43 
44  if (IsSessionReady()) {
45  // too many users in this session already, reject new ones
46  LogPrint(BCLog::PRIVATESEND, "DSACCEPT -- queue is already full!\n");
47  PushStatus(pfrom, STATUS_REJECTED, ERR_QUEUE_FULL, connman);
48  return;
49  }
50 
52  vRecv >> dsa;
53 
54  LogPrint(BCLog::PRIVATESEND, "DSACCEPT -- nDenom %d (%s) txCollateral %s", dsa.nDenom, CPrivateSend::DenominationToString(dsa.nDenom), dsa.txCollateral.ToString());
55 
56  auto mnList = deterministicMNManager->GetListAtChainTip();
57  auto dmn = mnList.GetValidMNByCollateral(activeMasternodeInfo.outpoint);
58  if (!dmn) {
59  PushStatus(pfrom, STATUS_REJECTED, ERR_MN_LIST, connman);
60  return;
61  }
62 
63  if (vecSessionCollaterals.empty()) {
64  {
65  TRY_LOCK(cs_vecqueue, lockRecv);
66  if (!lockRecv) return;
67 
68  for (const auto& q : vecPrivateSendQueue) {
69  if (q.masternodeOutpoint == activeMasternodeInfo.outpoint) {
70  // refuse to create another queue this often
71  LogPrint(BCLog::PRIVATESEND, "DSACCEPT -- last dsq is still in queue, refuse to mix\n");
72  PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman);
73  return;
74  }
75  }
76  }
77 
78  int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq();
79  int64_t nDsqThreshold = mmetaman.GetDsqThreshold(dmn->proTxHash, mnList.GetValidMNsCount());
80  if (nLastDsq != 0 && nDsqThreshold > mmetaman.GetDsqCount()) {
81  if (fLogIPs) {
82  LogPrint(BCLog::PRIVATESEND, "DSACCEPT -- last dsq too recent, must wait: peer=%d, addr=%s\n", pfrom->GetId(), pfrom->addr.ToString());
83  } else {
84  LogPrint(BCLog::PRIVATESEND, "DSACCEPT -- last dsq too recent, must wait: peer=%d\n", pfrom->GetId());
85  }
86  PushStatus(pfrom, STATUS_REJECTED, ERR_RECENT, connman);
87  return;
88  }
89  }
90 
91  PoolMessage nMessageID = MSG_NOERR;
92 
93  bool fResult = nSessionID == 0 ? CreateNewSession(dsa, nMessageID, connman)
94  : AddUserToExistingSession(dsa, nMessageID);
95  if (fResult) {
96  LogPrint(BCLog::PRIVATESEND, "DSACCEPT -- is compatible, please submit!\n");
97  PushStatus(pfrom, STATUS_ACCEPTED, nMessageID, connman);
98  return;
99  } else {
100  LogPrint(BCLog::PRIVATESEND, "DSACCEPT -- not compatible with existing transactions!\n");
101  PushStatus(pfrom, STATUS_REJECTED, nMessageID, connman);
102  return;
103  }
104 
105  } else if (strCommand == NetMsgType::DSQUEUE) {
107  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
108  if (g_enable_bip61) {
109  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
111  "Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION)));
112  }
113  return;
114  }
115 
116  CPrivateSendQueue dsq;
117  vRecv >> dsq;
118 
119  {
120  TRY_LOCK(cs_vecqueue, lockRecv);
121  if (!lockRecv) return;
122 
123  // process every dsq only once
124  for (const auto& q : vecPrivateSendQueue) {
125  if (q == dsq) {
126  return;
127  }
128  if (q.fReady == dsq.fReady && q.masternodeOutpoint == dsq.masternodeOutpoint) {
129  // no way the same mn can send another dsq with the same readiness this soon
130  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- Peer %s is sending WAY too many dsq messages for a masternode with collateral %s\n", pfrom->GetLogString(), dsq.masternodeOutpoint.ToStringShort());
131  return;
132  }
133  }
134  } // cs_vecqueue
135 
136  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- %s new\n", dsq.ToString());
137 
138  if (dsq.IsTimeOutOfBounds()) return;
139 
140  auto mnList = deterministicMNManager->GetListAtChainTip();
141  auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint);
142  if (!dmn) return;
143 
144  if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) {
145  LOCK(cs_main);
146  Misbehaving(pfrom->GetId(), 10);
147  return;
148  }
149 
150  if (!dsq.fReady) {
151  int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq();
152  int64_t nDsqThreshold = mmetaman.GetDsqThreshold(dmn->proTxHash, mnList.GetValidMNsCount());
153  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- nLastDsq: %d nDsqThreshold: %d nDsqCount: %d\n", nLastDsq, nDsqThreshold, mmetaman.GetDsqCount());
154  //don't allow a few nodes to dominate the queuing process
155  if (nLastDsq != 0 && nDsqThreshold > mmetaman.GetDsqCount()) {
156  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- Masternode %s is sending too many dsq messages\n", dmn->pdmnState->addr.ToString());
157  return;
158  }
159  mmetaman.AllowMixing(dmn->proTxHash);
160 
161  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString());
162 
163  TRY_LOCK(cs_vecqueue, lockRecv);
164  if (!lockRecv) return;
165  vecPrivateSendQueue.push_back(dsq);
166  dsq.Relay(connman);
167  }
168 
169  } else if (strCommand == NetMsgType::DSVIN) {
171  LogPrint(BCLog::PRIVATESEND, "DSVIN -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
172  if (g_enable_bip61) {
173  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
175  "Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION)));
176  }
177  PushStatus(pfrom, STATUS_REJECTED, ERR_VERSION, connman);
178  return;
179  }
180 
181  //do we have enough users in the current session?
182  if (!IsSessionReady()) {
183  LogPrint(BCLog::PRIVATESEND, "DSVIN -- session not complete!\n");
184  PushStatus(pfrom, STATUS_REJECTED, ERR_SESSION, connman);
185  return;
186  }
187 
188  CPrivateSendEntry entry;
189  vRecv >> entry;
190 
191  LogPrint(BCLog::PRIVATESEND, "DSVIN -- txCollateral %s", entry.txCollateral->ToString());
192 
193  PoolMessage nMessageID = MSG_NOERR;
194 
195  entry.addr = pfrom->addr;
196  if (AddEntry(connman, entry, nMessageID)) {
197  PushStatus(pfrom, STATUS_ACCEPTED, nMessageID, connman);
198  CheckPool(connman);
199  RelayStatus(STATUS_ACCEPTED, connman);
200  } else {
201  PushStatus(pfrom, STATUS_REJECTED, nMessageID, connman);
202  }
203 
204  } else if (strCommand == NetMsgType::DSSIGNFINALTX) {
206  LogPrint(BCLog::PRIVATESEND, "DSSIGNFINALTX -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
207  if (g_enable_bip61) {
208  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
210  "Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION)));
211  }
212  return;
213  }
214 
215  std::vector<CTxIn> vecTxIn;
216  vRecv >> vecTxIn;
217 
218  LogPrint(BCLog::PRIVATESEND, "DSSIGNFINALTX -- vecTxIn.size() %s\n", vecTxIn.size());
219 
220  int nTxInIndex = 0;
221  int nTxInsCount = (int)vecTxIn.size();
222 
223  for (const auto& txin : vecTxIn) {
224  nTxInIndex++;
225  if (!AddScriptSig(txin)) {
226  LogPrint(BCLog::PRIVATESEND, "DSSIGNFINALTX -- AddScriptSig() failed at %d/%d, session: %d\n", nTxInIndex, nTxInsCount, nSessionID);
227  RelayStatus(STATUS_REJECTED, connman);
228  return;
229  }
230  LogPrint(BCLog::PRIVATESEND, "DSSIGNFINALTX -- AddScriptSig() %d/%d success\n", nTxInIndex, nTxInsCount);
231  }
232  // all is good
233  CheckPool(connman);
234  }
235 }
236 
238 {
239  // MN side
240  vecSessionCollaterals.clear();
241 
244 }
245 
246 //
247 // Check the mixing progress and send client updates if a Masternode
248 //
250 {
251  if (!fMasternodeMode) return;
252 
253  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CheckPool -- entries count %lu\n", GetEntriesCount());
254 
255  // If we have an entry for each collateral, then create final tx
257  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CheckPool -- FINALIZE TRANSACTIONS\n");
258  CreateFinalTransaction(connman);
259  return;
260  }
261 
262  // Check for Time Out
263  // If we timed out while accepting entries, then if we have more than minimum, create final tx
266  // Punish misbehaving participants
267  ChargeFees(connman);
268  // Try to complete this session ignoring the misbehaving ones
269  CreateFinalTransaction(connman);
270  return;
271  }
272 
273  // If we have all of the signatures, try to compile the transaction
275  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CheckPool -- SIGNING\n");
276  CommitFinalTransaction(connman);
277  return;
278  }
279 }
280 
282 {
283  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CreateFinalTransaction -- FINALIZE TRANSACTIONS\n");
284 
285  CMutableTransaction txNew;
286 
287  // make our new transaction
288  for (int i = 0; i < GetEntriesCount(); i++) {
289  for (const auto& txout : vecEntries[i].vecTxOut) {
290  txNew.vout.push_back(txout);
291  }
292  for (const auto& txdsin : vecEntries[i].vecTxDSIn) {
293  txNew.vin.push_back(txdsin);
294  }
295  }
296 
297  sort(txNew.vin.begin(), txNew.vin.end(), CompareInputBIP69());
298  sort(txNew.vout.begin(), txNew.vout.end(), CompareOutputBIP69());
299 
300  finalMutableTransaction = txNew;
301  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CreateFinalTransaction -- finalMutableTransaction=%s", txNew.ToString());
302 
303  // request signatures from clients
306 }
307 
309 {
310  if (!fMasternodeMode) return; // check and relay final tx only on masternode
311 
313  uint256 hashTx = finalTransaction->GetHash();
314 
315  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CommitFinalTransaction -- finalTransaction=%s", finalTransaction->ToString());
316 
317  {
318  // See if the transaction is valid
319  TRY_LOCK(cs_main, lockMain);
320  CValidationState validationState;
321  mempool.PrioritiseTransaction(hashTx, 0.1 * COIN);
322  if (!lockMain || !AcceptToMemoryPool(mempool, validationState, finalTransaction, nullptr /* pfMissingInputs */, false /* bypass_limits */, maxTxFee /* nAbsurdFee */)) {
323  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CommitFinalTransaction -- AcceptToMemoryPool() error: Transaction not valid\n");
324  SetNull();
325  // not much we can do in this case, just notify clients
327  return;
328  }
329  }
330 
331  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CommitFinalTransaction -- CREATING DSTX\n");
332 
333  // create and sign masternode dstx transaction
334  if (!CPrivateSend::GetDSTX(hashTx)) {
336  dstxNew.Sign();
337  CPrivateSend::AddDSTX(dstxNew);
338  }
339 
340  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CommitFinalTransaction -- TRANSMITTING DSTX\n");
341 
342  CInv inv(MSG_DSTX, hashTx);
343  connman.RelayInv(inv);
344 
345  // Tell the clients it was successful
347 
348  // Randomly charge clients
349  ChargeRandomFees(connman);
350 
351  // Reset
352  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CommitFinalTransaction -- COMPLETED -- RESETTING\n");
353  SetNull();
354 }
355 
356 //
357 // Charge clients a fee if they're abusive
358 //
359 // Why bother? PrivateSend uses collateral to ensure abuse to the process is kept to a minimum.
360 // The submission and signing stages are completely separate. In the cases where
361 // a client submits a transaction then refused to sign, there must be a cost. Otherwise they
362 // would be able to do this over and over again and bring the mixing to a halt.
363 //
364 // How does this work? Messages to Masternodes come in via NetMsgType::DSVIN, these require a valid collateral
365 // transaction for the client to be able to enter the pool. This transaction is kept by the Masternode
366 // until the transaction is either complete or fails.
367 //
369 {
370  if (!fMasternodeMode) return;
371 
372  //we don't need to charge collateral for every offence.
373  if (GetRandInt(100) > 33) return;
374 
375  std::vector<CTransactionRef> vecOffendersCollaterals;
376 
378  for (const auto& txCollateral : vecSessionCollaterals) {
379  bool fFound = false;
380  for (const auto& entry : vecEntries) {
381  if (*entry.txCollateral == *txCollateral) {
382  fFound = true;
383  break;
384  }
385  }
386 
387  // This queue entry didn't send us the promised transaction
388  if (!fFound) {
389  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::ChargeFees -- found uncooperative node (didn't send transaction), found offence\n");
390  vecOffendersCollaterals.push_back(txCollateral);
391  }
392  }
393  }
394 
395  if (nState == POOL_STATE_SIGNING) {
396  // who didn't sign?
397  for (const auto& entry : vecEntries) {
398  for (const auto& txdsin : entry.vecTxDSIn) {
399  if (!txdsin.fHasSig) {
400  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::ChargeFees -- found uncooperative node (didn't sign), found offence\n");
401  vecOffendersCollaterals.push_back(entry.txCollateral);
402  }
403  }
404  }
405  }
406 
407  // no offences found
408  if (vecOffendersCollaterals.empty()) return;
409 
410  //mostly offending? Charge sometimes
411  if ((int)vecOffendersCollaterals.size() >= vecSessionCollaterals.size() - 1 && GetRandInt(100) > 33) return;
412 
413  //everyone is an offender? That's not right
414  if ((int)vecOffendersCollaterals.size() >= vecSessionCollaterals.size()) return;
415 
416  //charge one of the offenders randomly
417  std::random_shuffle(vecOffendersCollaterals.begin(), vecOffendersCollaterals.end());
418 
420  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::ChargeFees -- found uncooperative node (didn't %s transaction), charging fees: %s",
421  (nState == POOL_STATE_SIGNING) ? "sign" : "send", vecOffendersCollaterals[0]->ToString());
422  ConsumeCollateral(connman, vecOffendersCollaterals[0]);
423  }
424 }
425 
426 /*
427  Charge the collateral randomly.
428  Mixing is completely free, to pay miners we randomly pay the collateral of users.
429 
430  Collateral Fee Charges:
431 
432  Being that mixing has "no fees" we need to have some kind of cost associated
433  with using it to stop abuse. Otherwise it could serve as an attack vector and
434  allow endless transaction that would bloat Dash and make it unusable. To
435  stop these kinds of attacks 1 in 10 successful transactions are charged. This
436  adds up to a cost of 0.001DRK per transaction on average.
437 */
439 {
440  if (!fMasternodeMode) return;
441 
442  for (const auto& txCollateral : vecSessionCollaterals) {
443  if (GetRandInt(100) > 10) return;
444  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::ChargeRandomFees -- charging random fees, txCollateral=%s", txCollateral->ToString());
445  ConsumeCollateral(connman, txCollateral);
446  }
447 }
448 
450 {
451  LOCK(cs_main);
452  CValidationState validationState;
453  if (!AcceptToMemoryPool(mempool, validationState, txref, nullptr /* pfMissingInputs */, false /* bypass_limits */, 0 /* nAbsurdFee */)) {
454  LogPrint(BCLog::PRIVATESEND, "%s -- AcceptToMemoryPool failed\n", __func__);
455  } else {
456  connman.RelayTransaction(*txref);
457  LogPrint(BCLog::PRIVATESEND, "%s -- Collateral was consumed\n", __func__);
458  }
459 }
460 
462 {
463  if (!fMasternodeMode) return false;
464 
465  if (nState == POOL_STATE_IDLE) return false;
466 
468 
469  return GetTime() - nTimeLastSuccessfulStep >= nTimeout;
470 }
471 
472 //
473 // Check for extraneous timeout
474 //
476 {
477  if (!fMasternodeMode) return;
478 
479  CheckQueue();
480 
481  // Too early to do anything
482  if (!CPrivateSendServer::HasTimedOut()) return;
483 
484  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CheckTimeout -- %s timed out -- resetting\n",
485  (nState == POOL_STATE_SIGNING) ? "Signing" : "Session");
486  ChargeFees(connman);
487  SetNull();
488 }
489 
490 /*
491  Check to see if we're ready for submissions from clients
492  After receiving multiple dsa messages, the queue will switch to "accepting entries"
493  which is the active state right before merging the transaction
494 */
496 {
497  if (!fMasternodeMode) return;
498 
499  if (nState == POOL_STATE_QUEUE && IsSessionReady()) {
501 
503  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CheckForCompleteQueue -- queue is ready, signing and relaying (%s) "
504  "with %d participants\n", dsq.ToString(), vecSessionCollaterals.size());
505  dsq.Sign();
506  dsq.Relay(connman);
507  }
508 }
509 
510 // Check to make sure a given input matches an input in the pool and its scriptSig is valid
512 {
513  CMutableTransaction txNew;
514  txNew.vin.clear();
515  txNew.vout.clear();
516 
517  int i = 0;
518  int nTxInIndex = -1;
519  CScript sigPubKey = CScript();
520 
521  for (const auto& entry : vecEntries) {
522  for (const auto& txout : entry.vecTxOut) {
523  txNew.vout.push_back(txout);
524  }
525  for (const auto& txdsin : entry.vecTxDSIn) {
526  txNew.vin.push_back(txdsin);
527 
528  if (txdsin.prevout == txin.prevout) {
529  nTxInIndex = i;
530  sigPubKey = txdsin.prevPubKey;
531  }
532  i++;
533  }
534  }
535 
536  if (nTxInIndex >= 0) { //might have to do this one input at a time?
537  txNew.vin[nTxInIndex].scriptSig = txin.scriptSig;
538  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::IsInputScriptSigValid -- verifying scriptSig %s\n", ScriptToAsmStr(txin.scriptSig).substr(0, 24));
539  // TODO we're using amount=0 here but we should use the correct amount. This works because Dash ignores the amount while signing/verifying (only used in Bitcoin/Segwit)
540  if (!VerifyScript(txNew.vin[nTxInIndex].scriptSig, sigPubKey, SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC, MutableTransactionSignatureChecker(&txNew, nTxInIndex, 0))) {
541  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::IsInputScriptSigValid -- VerifyScript() failed on input %d\n", nTxInIndex);
542  return false;
543  }
544  } else {
545  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::IsInputScriptSigValid -- Failed to find matching input in pool, %s\n", txin.ToString());
546  return false;
547  }
548 
549  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::IsInputScriptSigValid -- Successfully validated input and scriptSig\n");
550  return true;
551 }
552 
553 //
554 // Add a client's transaction inputs/outputs to the pool
555 //
556 bool CPrivateSendServer::AddEntry(CConnman& connman, const CPrivateSendEntry& entry, PoolMessage& nMessageIDRet)
557 {
558  if (!fMasternodeMode) return false;
559 
560  if (GetEntriesCount() >= vecSessionCollaterals.size()) {
561  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- ERROR: entries is full!\n", __func__);
562  nMessageIDRet = ERR_ENTRIES_FULL;
563  return false;
564  }
565 
567  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- ERROR: collateral not valid!\n", __func__);
568  nMessageIDRet = ERR_INVALID_COLLATERAL;
569  return false;
570  }
571 
572  if (entry.vecTxDSIn.size() > PRIVATESEND_ENTRY_MAX_SIZE) {
573  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- ERROR: too many inputs! %d/%d\n", __func__, entry.vecTxDSIn.size(), PRIVATESEND_ENTRY_MAX_SIZE);
574  nMessageIDRet = ERR_MAXIMUM;
575  ConsumeCollateral(connman, entry.txCollateral);
576  return false;
577  }
578 
579  std::vector<CTxIn> vin;
580  for (const auto& txin : entry.vecTxDSIn) {
581  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- txin=%s\n", __func__, txin.ToString());
582 
583  for (const auto& entry : vecEntries) {
584  for (const auto& txdsin : entry.vecTxDSIn) {
585  if (txdsin.prevout == txin.prevout) {
586  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- ERROR: already have this txin in entries\n", __func__);
587  nMessageIDRet = ERR_ALREADY_HAVE;
588  // Two peers sent the same input? Can't really say who is the malicious one here,
589  // could be that someone is picking someone else's inputs randomly trying to force
590  // collateral consumption. Do not punish.
591  return false;
592  }
593  }
594  }
595  vin.emplace_back(txin);
596  }
597 
598  bool fConsumeCollateral{false};
599  if (!IsValidInOuts(vin, entry.vecTxOut, nMessageIDRet, &fConsumeCollateral)) {
600  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- ERROR! IsValidInOuts() failed: %s\n", __func__, CPrivateSend::GetMessageByID(nMessageIDRet));
601  if (fConsumeCollateral) {
602  ConsumeCollateral(connman, entry.txCollateral);
603  }
604  return false;
605  }
606 
607  vecEntries.push_back(entry);
608 
609  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- adding entry %d of %d required\n", __func__, GetEntriesCount(), CPrivateSend::GetMaxPoolParticipants());
610  nMessageIDRet = MSG_ENTRIES_ADDED;
611 
612  return true;
613 }
614 
616 {
617  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::AddScriptSig -- scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0, 24));
618 
619  for (const auto& entry : vecEntries) {
620  for (const auto& txdsin : entry.vecTxDSIn) {
621  if (txdsin.scriptSig == txinNew.scriptSig) {
622  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::AddScriptSig -- already exists\n");
623  return false;
624  }
625  }
626  }
627 
628  if (!IsInputScriptSigValid(txinNew)) {
629  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::AddScriptSig -- Invalid scriptSig\n");
630  return false;
631  }
632 
633  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::AddScriptSig -- scriptSig=%s new\n", ScriptToAsmStr(txinNew.scriptSig).substr(0, 24));
634 
635  for (auto& txin : finalMutableTransaction.vin) {
636  if (txin.prevout == txinNew.prevout && txin.nSequence == txinNew.nSequence) {
637  txin.scriptSig = txinNew.scriptSig;
638  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::AddScriptSig -- adding to finalMutableTransaction, scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0, 24));
639  }
640  }
641  for (int i = 0; i < GetEntriesCount(); i++) {
642  if (vecEntries[i].AddScriptSig(txinNew)) {
643  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::AddScriptSig -- adding to entries, scriptSig=%s\n", ScriptToAsmStr(txinNew.scriptSig).substr(0, 24));
644  return true;
645  }
646  }
647 
648  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::AddScriptSig -- Couldn't set sig!\n");
649  return false;
650 }
651 
652 // Check to make sure everything is signed
654 {
655  for (const auto& entry : vecEntries) {
656  for (const auto& txdsin : entry.vecTxDSIn) {
657  if (!txdsin.fHasSig) return false;
658  }
659  }
660 
661  return true;
662 }
663 
665 {
666  if (!fMasternodeMode) return false;
667 
668  // is denom even something legit?
670  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- denom not valid!\n", __func__);
671  nMessageIDRet = ERR_DENOM;
672  return false;
673  }
674 
675  // check collateral
677  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- collateral not valid!\n", __func__);
678  nMessageIDRet = ERR_INVALID_COLLATERAL;
679  return false;
680  }
681 
682  return true;
683 }
684 
686 {
687  if (!fMasternodeMode || nSessionID != 0) return false;
688 
689  // new session can only be started in idle mode
690  if (nState != POOL_STATE_IDLE) {
691  nMessageIDRet = ERR_MODE;
692  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CreateNewSession -- incompatible mode: nState=%d\n", nState);
693  return false;
694  }
695 
696  if (!IsAcceptableDSA(dsa, nMessageIDRet)) {
697  return false;
698  }
699 
700  // start new session
701  nMessageIDRet = MSG_NOERR;
702  nSessionID = GetRandInt(999999) + 1;
703  nSessionDenom = dsa.nDenom;
704 
706 
707  if (!fUnitTest) {
708  //broadcast that I'm accepting entries, only if it's the first entry through
710  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CreateNewSession -- signing and relaying new queue: %s\n", dsq.ToString());
711  dsq.Sign();
712  dsq.Relay(connman);
713  vecPrivateSendQueue.push_back(dsq);
714  }
715 
717  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::CreateNewSession -- new session created, nSessionID: %d nSessionDenom: %d (%s) vecSessionCollaterals.size(): %d CPrivateSend::GetMaxPoolParticipants(): %d\n",
719 
720  return true;
721 }
722 
724 {
725  if (!fMasternodeMode || nSessionID == 0 || IsSessionReady()) return false;
726 
727  if (!IsAcceptableDSA(dsa, nMessageIDRet)) {
728  return false;
729  }
730 
731  // we only add new users to an existing session when we are in queue mode
732  if (nState != POOL_STATE_QUEUE) {
733  nMessageIDRet = ERR_MODE;
734  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::AddUserToExistingSession -- incompatible mode: nState=%d\n", nState);
735  return false;
736  }
737 
738  if (dsa.nDenom != nSessionDenom) {
739  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::AddUserToExistingSession -- incompatible denom %d (%s) != nSessionDenom %d (%s)\n",
741  nMessageIDRet = ERR_DENOM;
742  return false;
743  }
744 
745  // count new user as accepted to an existing session
746 
747  nMessageIDRet = MSG_NOERR;
749 
750  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::AddUserToExistingSession -- new user accepted, nSessionID: %d nSessionDenom: %d (%s) vecSessionCollaterals.size(): %d CPrivateSend::GetMaxPoolParticipants(): %d\n",
752 
753  return true;
754 }
755 
756 // Returns true if either max size has been reached or if the mix timed out and min size was reached
758 {
759  if (nState == POOL_STATE_QUEUE) {
761  return true;
762  }
764  return true;
765  }
766  }
768  return true;
769  }
770  return false;
771 }
772 
774 {
775  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- nSessionID: %d nSessionDenom: %d (%s)\n",
777 
778  // final mixing tx with empty signatures should be relayed to mixing participants only
779  for (const auto& entry : vecEntries) {
780  bool fOk = connman.ForNode(entry.addr, [&txFinal, &connman, this](CNode* pnode) {
781  CNetMsgMaker msgMaker(pnode->GetSendVersion());
782  connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSFINALTX, nSessionID, txFinal));
783  return true;
784  });
785  if (!fOk) {
786  // no such node? maybe this client disconnected or our own connection went down
787  RelayStatus(STATUS_REJECTED, connman);
788  break;
789  }
790  }
791 }
792 
793 void CPrivateSendServer::PushStatus(CNode* pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, CConnman& connman)
794 {
795  if (!pnode) return;
796  CPrivateSendStatusUpdate psssup(nSessionID, nState, 0, nStatusUpdate, nMessageID);
797  connman.PushMessage(pnode, CNetMsgMaker(pnode->GetSendVersion()).Make(NetMsgType::DSSTATUSUPDATE, psssup));
798 }
799 
800 void CPrivateSendServer::RelayStatus(PoolStatusUpdate nStatusUpdate, CConnman& connman, PoolMessage nMessageID)
801 {
802  unsigned int nDisconnected{};
803  // status updates should be relayed to mixing participants only
804  for (const auto& entry : vecEntries) {
805  // make sure everyone is still connected
806  bool fOk = connman.ForNode(entry.addr, [&nStatusUpdate, &nMessageID, &connman, this](CNode* pnode) {
807  PushStatus(pnode, nStatusUpdate, nMessageID, connman);
808  return true;
809  });
810  if (!fOk) {
811  // no such node? maybe this client disconnected or our own connection went down
812  ++nDisconnected;
813  }
814  }
815  if (nDisconnected == 0) return; // all is clear
816 
817  // something went wrong
818  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- can't continue, %llu client(s) disconnected, nSessionID: %d nSessionDenom: %d (%s)\n",
820 
821  // notify everyone else that this session should be terminated
822  for (const auto& entry : vecEntries) {
823  connman.ForNode(entry.addr, [&connman, this](CNode* pnode) {
824  PushStatus(pnode, STATUS_REJECTED, MSG_NOERR, connman);
825  return true;
826  });
827  }
828 
829  if (nDisconnected == vecEntries.size()) {
830  // all clients disconnected, there is probably some issues with our own connection
831  // do not charge any fees, just reset the pool
832  SetNull();
833  }
834 }
835 
837 {
838  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::%s -- nSessionID: %d nSessionDenom: %d (%s)\n",
840 
841  // final mixing tx with empty signatures should be relayed to mixing participants only
842  for (const auto& entry : vecEntries) {
843  bool fOk = connman.ForNode(entry.addr, [&nMessageID, &connman, this](CNode* pnode) {
844  CNetMsgMaker msgMaker(pnode->GetSendVersion());
845  connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSCOMPLETE, nSessionID, nMessageID));
846  return true;
847  });
848  if (!fOk) {
849  // no such node? maybe client disconnected or our own connection went down
850  RelayStatus(STATUS_REJECTED, connman);
851  break;
852  }
853  }
854 }
855 
857 {
858  if (!fMasternodeMode) return;
859 
860  if (nStateNew == POOL_STATE_ERROR) {
861  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::SetState -- Can't set state to ERROR as a Masternode. \n");
862  return;
863  }
864 
865  LogPrint(BCLog::PRIVATESEND, "CPrivateSendServer::SetState -- nState: %d, nStateNew: %d\n", nState, nStateNew);
867  nState = nStateNew;
868 }
869 
871 {
872  if (!fMasternodeMode) return; // only run on masternodes
873 
875 
877  privateSendServer.CheckPool(connman);
879 }
880 
882 {
883  obj.clear();
884  obj.setObject();
885  obj.push_back(Pair("queue_size", GetQueueSize()));
887  obj.push_back(Pair("state", GetStateString()));
888  obj.push_back(Pair("entries_count", GetEntriesCount()));
889 }
CTxMemPool mempool
bool AddEntry(CConnman &connman, const CPrivateSendEntry &entry, PoolMessage &nMessageIDRet)
Add a clients entry to the pool.
CMasternodeSync masternodeSync
int GetSendVersion() const
Definition: net.cpp:887
CPrivateSendServer privateSendServer
std::string ToString(bool fUseGetnameinfo=true) const
Definition: netaddress.cpp:581
const char * DSACCEPT
Definition: protocol.cpp:47
int GetRandInt(int nMax)
Definition: random.cpp:379
#define TRY_LOCK(cs, name)
Definition: sync.h:180
std::vector< CPrivateSendEntry > vecEntries
Definition: privatesend.h:364
bool ShutdownRequested()
Definition: init.cpp:179
#define strprintf
Definition: tinyformat.h:1066
CAmount maxTxFee
Absolute maximum transaction fee (in duffs) used by wallet and mempool (rejects high fee in sendrawtr...
Definition: validation.cpp:247
void CheckTimeout(CConnman &connman)
inv message data
Definition: protocol.h:429
std::vector< CTxIn > vin
Definition: transaction.h:293
static const CAmount COIN
Definition: amount.h:14
int64_t GetDsqThreshold(const uint256 &proTxHash, int nMnCount)
bool AddUserToExistingSession(const CPrivateSendAccept &dsa, PoolMessage &nMessageIDRet)
std::vector< CTxDSIn > vecTxDSIn
Definition: privatesend.h:176
A currently in progress mixing merge and denomination information.
Definition: privatesend.h:215
const char * DSVIN
Definition: protocol.cpp:48
static int GetMaxPoolParticipants()
Definition: privatesend.h:452
Implementation of BIP69 https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki.
Definition: transaction.h:352
CCriticalSection cs_main
Definition: validation.cpp:213
const char * DSSTATUSUPDATE
Definition: protocol.cpp:52
UniValue ValueFromAmount(const CAmount &amount)
Definition: core_write.cpp:25
bool IsInputScriptSigValid(const CTxIn &txin)
Check to make sure a given input matches an input in the pool and its scriptSig is valid...
void PushMessage(CNode *pnode, CSerializedNetMsg &&msg)
Definition: net.cpp:3733
PoolMessage
Definition: privatesend.h:33
bool Relay(CConnman &connman)
Definition: privatesend.cpp:74
std::string ToString() const
Definition: transaction.cpp:36
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:103
CMutableTransaction finalMutableTransaction
Definition: privatesend.h:371
static const int PRIVATESEND_QUEUE_TIMEOUT
Definition: privatesend.h:24
bool IsBlockchainSynced()
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:345
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
static const unsigned char REJECT_OBSOLETE
Definition: validation.h:14
std::vector< CTxOut > vecTxOut
Definition: privatesend.h:177
CMasternodeMetaMan mmetaman
void RelayFinalTransaction(const CTransaction &txFinal, CConnman &connman)
Relay mixing Messages.
void Misbehaving(NodeId pnode, int howmuch, const std::string &message)
Increase a node&#39;s misbehavior score.
int64_t GetTime()
Return system time (or mocked time, if set)
Definition: utiltime.cpp:22
static CTransactionRef MakeTransactionRef()
Definition: transaction.h:346
bool fMasternodeMode
Definition: util.cpp:93
PoolState
Definition: privatesend.h:63
bool ForNode(NodeId id, std::function< bool(const CNode *pnode)> cond, std::function< bool(CNode *pnode)> func)
Definition: net.cpp:3795
static int GetMinPoolParticipants()
Get the minimum/maximum number of participants for the pool.
Definition: privatesend.h:449
bool push_back(const UniValue &val)
Definition: univalue.cpp:110
CActiveMasternodeInfo activeMasternodeInfo
std::string ScriptToAsmStr(const CScript &script, const bool fAttemptSighashDecode=false)
Create the assembly string representation of a CScript object.
Definition: core_write.cpp:86
CTransactionRef txCollateral
Definition: privatesend.h:178
static bool IsCollateralValid(const CTransaction &txCollateral)
If the collateral is valid given by a client.
void ChargeRandomFees(CConnman &connman)
Rarely charge fees to pay miners.
void GetJsonInfo(UniValue &obj) const
An input of a transaction.
Definition: transaction.h:70
static CPrivateSendBroadcastTx GetDSTX(const uint256 &hash)
#define LOCK(cs)
Definition: sync.h:178
CCriticalSection cs_vecqueue
Definition: privatesend.h:400
Definition: privatesend.h:173
void CheckPool(CConnman &connman)
Check for process.
bool CreateNewSession(const CPrivateSendAccept &dsa, PoolMessage &nMessageIDRet, CConnman &connman)
int GetQueueSize() const
Definition: privatesend.h:412
std::vector< CPrivateSendQueue > vecPrivateSendQueue
Definition: privatesend.h:403
Definition: net.h:136
bool IsAcceptableDSA(const CPrivateSendAccept &dsa, PoolMessage &nMessageIDRet)
Is this nDenom and txCollateral acceptable?
NodeId GetId() const
Definition: net.h:973
static std::pair< std::string, UniValue > Pair(const char *cKey, const char *cVal)
Definition: univalue.h:185
static void AddDSTX(const CPrivateSendBroadcastTx &dstx)
void ProcessMessage(CNode *pfrom, const std::string &strCommand, CDataStream &vRecv, CConnman &connman)
void RelayStatus(PoolStatusUpdate nStatusUpdate, CConnman &connman, PoolMessage nMessageID=MSG_NOERR)
std::vector< CTxOut > vout
Definition: transaction.h:294
void CheckForCompleteQueue(CConnman &connman)
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey, unsigned int flags, const BaseSignatureChecker &checker, ScriptError *serror)
const char * DSSIGNFINALTX
Definition: protocol.cpp:50
bool IsSessionReady()
Do we have enough users to take entries?
PoolStatusUpdate
Definition: privatesend.h:75
bool AddScriptSig(const CTxIn &txin)
Add signature to a txin.
static const int PRIVATESEND_SIGNING_TIMEOUT
Definition: privatesend.h:25
const char * REJECT
The reject message informs the receiving node that one of its previous messages has been rejected...
Definition: protocol.cpp:37
void DoMaintenance(CConnman &connman)
const CAddress addr
Definition: net.h:834
CScript scriptSig
Definition: transaction.h:74
#define LogPrint(category,...)
Definition: util.h:214
bool IsSignaturesComplete()
Check that all inputs are signed. (Are all inputs signed?)
bool fLogIPs
Definition: util.cpp:115
Capture information about block/transaction validation.
Definition: validation.h:22
256-bit opaque blob.
Definition: uint256.h:123
std::string GetStateString() const
void AllowMixing(const uint256 &proTxHash)
static bool IsValidDenomination(int nDenom)
Helper class to store mixing transaction (tx) information.
Definition: privatesend.h:291
std::string ToString() const
Definition: transaction.cpp:71
void PushStatus(CNode *pnode, PoolStatusUpdate nStatusUpdate, PoolMessage nMessageID, CConnman &connman)
int GetEntriesCount() const
Definition: privatesend.h:393
const char * DSQUEUE
Definition: protocol.cpp:54
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:389
uint32_t nSequence
Definition: transaction.h:75
bool AcceptToMemoryPool(CTxMemPool &pool, CValidationState &state, const CTransactionRef &tx, bool *pfMissingInputs, bool bypass_limits, const CAmount nAbsurdFee, bool fDryRun)
(try to) add transaction to memory pool
Definition: validation.cpp:890
void RelayCompletedTransaction(PoolMessage nMessageID, CConnman &connman)
int64_t GetAdjustedTime()
Definition: timedata.cpp:35
static const int MIN_PRIVATESEND_PEER_PROTO_VERSION
minimum peer version accepted by mixing pool
Definition: privatesend.h:28
bool Sign()
Sign this mixing transaction.
Definition: privatesend.cpp:45
static std::string GetMessageByID(PoolMessage nMessageID)
std::string GetLogString() const
Definition: net.cpp:750
bool setObject()
Definition: univalue.cpp:103
bool IsValidInOuts(const std::vector< CTxIn > &vin, const std::vector< CTxOut > &vout, PoolMessage &nMessageIDRet, bool *fConsumeCollateralRet) const
void RelayInv(CInv &inv, const int minProtoVersion=MIN_PEER_PROTO_VERSION, bool fAllowMasternodeConnections=false)
Definition: net.cpp:3482
std::atomic< int > nVersion
Definition: net.h:838
Used to keep track of current status of mixing pool.
void SetState(PoolState nStateNew)
A mutable version of CTransaction.
Definition: transaction.h:291
void CommitFinalTransaction(CConnman &connman)
void clear()
Definition: univalue.cpp:17
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:198
Information about a peer.
Definition: net.h:800
CMutableTransaction txCollateral
Definition: privatesend.h:147
void RelayTransaction(const CTransaction &tx)
Definition: net.cpp:3465
COutPoint prevout
Definition: transaction.h:73
std::string ToString() const
Definition: privatesend.h:277
static CAmount DenominationToAmount(int nDenom)
void CreateFinalTransaction(CConnman &connman)
void PrioritiseTransaction(const uint256 &hash, const CAmount &nFeeDelta)
Affect CreateNewBlock prioritisation of transactions.
Definition: txmempool.cpp:1317
bool g_enable_bip61
Enable BIP61 (sending reject messages)
CMasternodeMetaInfoPtr GetMetaInfo(const uint256 &proTxHash, bool fCreate=true)
static std::string DenominationToString(int nDenom)
std::vector< CTransactionRef > vecSessionCollaterals
void ConsumeCollateral(CConnman &connman, const CTransactionRef &txref)
Consume collateral in cases when peer misbehaved.
static const size_t PRIVATESEND_ENTRY_MAX_SIZE
Definition: privatesend.h:30
void ChargeFees(CConnman &connman)
Charge fees to bad actors (Charge clients a fee if they&#39;re abusive)
Released under the MIT license