Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

privatesend-client.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 
7 #include <consensus/validation.h>
8 #include <core_io.h>
9 #include <init.h>
13 #include <netmessagemaker.h>
14 #include <script/sign.h>
15 #include <txmempool.h>
16 #include <util.h>
17 #include <utilmoneystr.h>
18 #include <validation.h>
19 #include <wallet/coincontrol.h>
20 #include <wallet/fees.h>
21 
22 #include <memory>
23 #include <univalue.h>
24 
26 
27 void CPrivateSendClientManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
28 {
29  if (fMasternodeMode) return;
30  if (!fEnablePrivateSend) return;
31  if (!masternodeSync.IsBlockchainSynced()) return;
32 
33  if (!CheckDiskSpace()) {
34  ResetPool();
35  fPrivateSendRunning = false;
36  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::ProcessMessage -- Not enough disk space, disabling PrivateSend.\n");
37  return;
38  }
39 
40  if (strCommand == NetMsgType::DSQUEUE) {
42  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
43  if (g_enable_bip61) {
44  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
46  "Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION)));
47  }
48  return;
49  }
50 
52  vRecv >> dsq;
53 
54  {
55  TRY_LOCK(cs_vecqueue, lockRecv);
56  if (!lockRecv) return;
57 
58  // process every dsq only once
59  for (const auto& q : vecPrivateSendQueue) {
60  if (q == dsq) {
61  return;
62  }
63  if (q.fReady == dsq.fReady && q.masternodeOutpoint == dsq.masternodeOutpoint) {
64  // no way the same mn can send another dsq with the same readiness this soon
65  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());
66  return;
67  }
68  }
69  } // cs_vecqueue
70 
71  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- %s new\n", dsq.ToString());
72 
73  if (dsq.IsTimeOutOfBounds()) return;
74 
75  auto mnList = deterministicMNManager->GetListAtChainTip();
76  auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint);
77  if (!dmn) return;
78 
79  if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) {
80  LOCK(cs_main);
81  Misbehaving(pfrom->GetId(), 10);
82  return;
83  }
84 
85  // if the queue is ready, submit if we can
86  if (dsq.fReady) {
88  for (auto& session : deqSessions) {
89  CDeterministicMNCPtr mnMixing;
90  if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->pdmnState->addr == dmn->pdmnState->addr && session.GetState() == POOL_STATE_QUEUE) {
91  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- PrivateSend queue (%s) is ready on masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString());
92  session.SubmitDenominate(connman);
93  return;
94  }
95  }
96  } else {
97  int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq();
98  int64_t nDsqThreshold = mmetaman.GetDsqThreshold(dmn->proTxHash, mnList.GetValidMNsCount());
99  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- nLastDsq: %d nDsqThreshold: %d nDsqCount: %d\n", nLastDsq, nDsqThreshold, mmetaman.GetDsqCount());
100  // don't allow a few nodes to dominate the queuing process
101  if (nLastDsq != 0 && nDsqThreshold > mmetaman.GetDsqCount()) {
102  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- Masternode %s is sending too many dsq messages\n", dmn->proTxHash.ToString());
103  return;
104  }
105 
106  mmetaman.AllowMixing(dmn->proTxHash);
107 
108  LogPrint(BCLog::PRIVATESEND, "DSQUEUE -- new PrivateSend queue (%s) from masternode %s\n", dsq.ToString(), dmn->pdmnState->addr.ToString());
109 
111  for (auto& session : deqSessions) {
112  CDeterministicMNCPtr mnMixing;
113  if (session.GetMixingMasternodeInfo(mnMixing) && mnMixing->collateralOutpoint == dsq.masternodeOutpoint) {
114  dsq.fTried = true;
115  }
116  }
117 
118  TRY_LOCK(cs_vecqueue, lockRecv);
119  if (!lockRecv) return;
120  vecPrivateSendQueue.push_back(dsq);
121  dsq.Relay(connman);
122  }
123 
124  } else if (strCommand == NetMsgType::DSSTATUSUPDATE ||
125  strCommand == NetMsgType::DSFINALTX ||
126  strCommand == NetMsgType::DSCOMPLETE) {
128  for (auto& session : deqSessions) {
129  session.ProcessMessage(pfrom, strCommand, vRecv, connman);
130  }
131  }
132 }
133 
134 void CPrivateSendClientSession::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
135 {
136  if (fMasternodeMode) return;
138  if (!masternodeSync.IsBlockchainSynced()) return;
139 
140  if (strCommand == NetMsgType::DSSTATUSUPDATE) {
142  LogPrint(BCLog::PRIVATESEND, "DSSTATUSUPDATE -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
143  if (g_enable_bip61) {
144  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
146  "Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION)));
147  }
148  return;
149  }
150 
151  if (!mixingMasternode) return;
152  if (mixingMasternode->pdmnState->addr != pfrom->addr) {
153  return;
154  }
155 
157  vRecv >> psssup;
158 
159  ProcessPoolStateUpdate(psssup);
160 
161  } else if (strCommand == NetMsgType::DSFINALTX) {
163  LogPrint(BCLog::PRIVATESEND, "DSFINALTX -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
164  if (g_enable_bip61) {
165  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
167  "Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION)));
168  }
169  return;
170  }
171 
172  if (!mixingMasternode) return;
173  if (mixingMasternode->pdmnState->addr != pfrom->addr) {
174  return;
175  }
176 
177  int nMsgSessionID;
178  vRecv >> nMsgSessionID;
179  CTransaction txNew(deserialize, vRecv);
180 
181  if (nSessionID != nMsgSessionID) {
182  LogPrint(BCLog::PRIVATESEND, "DSFINALTX -- message doesn't match current PrivateSend session: nSessionID: %d nMsgSessionID: %d\n", nSessionID, nMsgSessionID);
183  return;
184  }
185 
186  LogPrint(BCLog::PRIVATESEND, "DSFINALTX -- txNew %s", txNew.ToString());
187 
188  // check to see if input is spent already? (and probably not confirmed)
189  SignFinalTransaction(txNew, pfrom, connman);
190 
191  } else if (strCommand == NetMsgType::DSCOMPLETE) {
193  LogPrint(BCLog::PRIVATESEND, "DSCOMPLETE -- peer=%d using obsolete version %i\n", pfrom->GetId(), pfrom->nVersion);
194  if (g_enable_bip61) {
195  connman.PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::REJECT, strCommand,
197  "Version must be %d or greater", MIN_PRIVATESEND_PEER_PROTO_VERSION)));
198  }
199  return;
200  }
201 
202  if (!mixingMasternode) return;
203  if (mixingMasternode->pdmnState->addr != pfrom->addr) {
204  LogPrint(BCLog::PRIVATESEND, "DSCOMPLETE -- message doesn't match current Masternode: infoMixingMasternode=%s addr=%s\n", mixingMasternode->pdmnState->addr.ToString(), pfrom->addr.ToString());
205  return;
206  }
207 
208  int nMsgSessionID;
209  PoolMessage nMsgMessageID;
210  vRecv >> nMsgSessionID >> nMsgMessageID;
211 
212  if (nMsgMessageID < MSG_POOL_MIN || nMsgMessageID > MSG_POOL_MAX) {
213  LogPrint(BCLog::PRIVATESEND, "DSCOMPLETE -- nMsgMessageID is out of bounds: %d\n", nMsgMessageID);
214  return;
215  }
216 
217  if (nSessionID != nMsgSessionID) {
218  LogPrint(BCLog::PRIVATESEND, "DSCOMPLETE -- message doesn't match current PrivateSend session: nSessionID: %d nMsgSessionID: %d\n", nSessionID, nMsgSessionID);
219  return;
220  }
221 
222  LogPrint(BCLog::PRIVATESEND, "DSCOMPLETE -- nMsgSessionID %d nMsgMessageID %d (%s)\n", nMsgSessionID, nMsgMessageID, CPrivateSend::GetMessageByID(nMsgMessageID));
223 
224  CompletedTransaction(nMsgMessageID);
225  }
226 }
227 
229 {
231  UnlockCoins();
233  SetNull();
234 }
235 
237 {
240  vecMasternodesUsed.clear();
241  for (auto& session : deqSessions) {
242  session.ResetPool();
243  }
244  deqSessions.clear();
245 }
246 
248 {
249  // Client side
250  mixingMasternode = nullptr;
252 
254 }
255 
256 //
257 // Unlock coins after mixing fails or succeeds
258 //
260 {
262 
263  while (true) {
264  TRY_LOCK(GetWallets()[0]->cs_wallet, lockWallet);
265  if (!lockWallet) {
266  MilliSleep(50);
267  continue;
268  }
269  for (const auto& outpoint : vecOutPointLocked)
270  GetWallets()[0]->UnlockCoin(outpoint);
271  break;
272  }
273 
274  vecOutPointLocked.clear();
275 }
276 
277 std::string CPrivateSendClientSession::GetStatus(bool fWaitForBlock)
278 {
279  static int nStatusMessageProgress = 0;
280  nStatusMessageProgress += 10;
281  std::string strSuffix = "";
282 
283  if (fWaitForBlock || !masternodeSync.IsBlockchainSynced()) {
284  return strAutoDenomResult;
285  }
286 
287  switch (nState) {
288  case POOL_STATE_IDLE:
289  return _("PrivateSend is idle.");
290  case POOL_STATE_QUEUE:
291  if (nStatusMessageProgress % 70 <= 30)
292  strSuffix = ".";
293  else if (nStatusMessageProgress % 70 <= 50)
294  strSuffix = "..";
295  else if (nStatusMessageProgress % 70 <= 70)
296  strSuffix = "...";
297  return strprintf(_("Submitted to masternode, waiting in queue %s"), strSuffix);
299  return strAutoDenomResult;
300  case POOL_STATE_SIGNING:
301  if (nStatusMessageProgress % 70 <= 40)
302  return _("Found enough users, signing ...");
303  else if (nStatusMessageProgress % 70 <= 50)
304  strSuffix = ".";
305  else if (nStatusMessageProgress % 70 <= 60)
306  strSuffix = "..";
307  else if (nStatusMessageProgress % 70 <= 70)
308  strSuffix = "...";
309  return strprintf(_("Found enough users, signing ( waiting %s )"), strSuffix);
310  case POOL_STATE_ERROR:
311  return _("PrivateSend request incomplete:") + " " + strLastMessage + " " + _("Will retry...");
312  default:
313  return strprintf(_("Unknown state: id = %u"), nState);
314  }
315 }
316 
318 {
320  std::string strStatus;
321  bool fWaitForBlock = WaitForAnotherBlock();
322 
323  for (auto& session : deqSessions) {
324  strStatus += session.GetStatus(fWaitForBlock) + "; ";
325  }
326  return strStatus;
327 }
328 
330 {
332  std::string strSessionDenoms;
333 
334  for (auto& session : deqSessions) {
335  strSessionDenoms += CPrivateSend::DenominationToString(session.nSessionDenom) + "; ";
336  }
337  return strSessionDenoms.empty() ? "N/A" : strSessionDenoms;
338 }
339 
341 {
342  ret = mixingMasternode;
343  return ret != nullptr;
344 }
345 
346 bool CPrivateSendClientManager::GetMixingMasternodesInfo(std::vector<CDeterministicMNCPtr>& vecDmnsRet) const
347 {
349  for (const auto& session : deqSessions) {
351  if (session.GetMixingMasternodeInfo(dmn)) {
352  vecDmnsRet.push_back(dmn);
353  }
354  }
355  return !vecDmnsRet.empty();
356 }
357 
358 //
359 // Check session timeouts
360 //
362 {
363  if (fMasternodeMode) return false;
364 
365  if (nState == POOL_STATE_IDLE) return false;
366 
367  if (nState == POOL_STATE_ERROR) {
368  if (GetTime() - nTimeLastSuccessfulStep >= 10) {
369  // reset after being in POOL_STATE_ERROR for 10 or more seconds
370  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- resetting session %d\n", __func__, nSessionID);
371  SetNull();
372  }
373  return false;
374  }
375 
376  int nLagTime = 10; // give the server a few extra seconds before resetting.
378  bool fTimeout = GetTime() - nTimeLastSuccessfulStep >= nTimeout + nLagTime;
379 
380  if (!fTimeout) return false;
381 
382  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- %s %d timed out (%ds)\n", __func__,
383  (nState == POOL_STATE_SIGNING) ? "Signing at session" : "Session", nSessionID, nTimeout);
384 
386  UnlockCoins();
390 
391  return true;
392 }
393 
394 //
395 // Check all queues and sessions for timeouts
396 //
398 {
399  if (fMasternodeMode) return;
400 
401  CheckQueue();
402 
403  if (!fEnablePrivateSend || !fPrivateSendRunning) return;
404 
406  for (auto& session : deqSessions) {
407  if (session.CheckTimeout()) {
408  strAutoDenomResult = _("Session timed out.");
409  }
410  }
411 }
412 
413 //
414 // Execute a mixing denomination via a Masternode.
415 // This is only ran from clients
416 //
417 bool CPrivateSendClientSession::SendDenominate(const std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsIn, CConnman& connman)
418 {
419  if (fMasternodeMode) {
420  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SendDenominate -- PrivateSend from a Masternode is not supported currently.\n");
421  return false;
422  }
423 
425  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClient:SendDenominate -- PrivateSend collateral not set\n");
426  return false;
427  }
428 
429  // we should already be connected to a Masternode
430  if (!nSessionID) {
431  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SendDenominate -- No Masternode has been selected yet.\n");
432  UnlockCoins();
434  SetNull();
435  return false;
436  }
437 
438  if (!CheckDiskSpace()) {
439  UnlockCoins();
441  SetNull();
442  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SendDenominate -- Not enough disk space.\n");
443  return false;
444  }
445 
447  strLastMessage = "";
448 
449  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SendDenominate -- Added transaction to pool.\n");
450 
451  CMutableTransaction tx; // for debug purposes only
452  std::vector<CTxDSIn> vecTxDSInTmp;
453  std::vector<CTxOut> vecTxOutTmp;
454 
455  for (const auto& pair : vecPSInOutPairsIn) {
456  vecTxDSInTmp.emplace_back(pair.first);
457  vecTxOutTmp.emplace_back(pair.second);
458  tx.vin.emplace_back(pair.first);
459  tx.vout.emplace_back(pair.second);
460  }
461 
462  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SendDenominate -- Submitting partial tx %s", tx.ToString());
463 
464  // store our entry for later use
465  vecEntries.emplace_back(vecTxDSInTmp, vecTxOutTmp, txMyCollateral);
466  RelayIn(vecEntries.back(), connman);
468 
469  return true;
470 }
471 
472 // Process incoming messages from Masternode updating the progress of mixing
474 {
475  if (fMasternodeMode) return;
476 
477  // do not update state when mixing client state is one of these
478  if (nState == POOL_STATE_IDLE || nState == POOL_STATE_ERROR) return;
479 
480  if (psssup.nState < POOL_STATE_MIN || psssup.nState > POOL_STATE_MAX) {
481  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- psssup.nState is out of bounds: %d\n", __func__, psssup.nState);
482  return;
483  }
484 
485  if (psssup.nMessageID < MSG_POOL_MIN || psssup.nMessageID > MSG_POOL_MAX) {
486  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- psssup.nMessageID is out of bounds: %d\n", __func__, psssup.nMessageID);
487  return;
488  }
489 
490  std::string strMessageTmp = CPrivateSend::GetMessageByID(psssup.nMessageID);
491  strAutoDenomResult = _("Masternode:") + " " + strMessageTmp;
492 
493  switch (psssup.nStatusUpdate) {
494  case STATUS_REJECTED: {
495  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- rejected by Masternode: %s\n", __func__, strMessageTmp);
497  UnlockCoins();
500  strLastMessage = strMessageTmp;
501  break;
502  }
503  case STATUS_ACCEPTED: {
504  if (nState == psssup.nState && psssup.nState == POOL_STATE_QUEUE && nSessionID == 0 && psssup.nSessionID != 0) {
505  // new session id should be set only in POOL_STATE_QUEUE state
506  nSessionID = psssup.nSessionID;
508  strMessageTmp += strprintf(" Set nSessionID to %d.", nSessionID);
509  }
510  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- accepted by Masternode: %s\n", __func__, strMessageTmp);
511  break;
512  }
513  default: {
514  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- psssup.nStatusUpdate is out of bounds: %d\n", __func__, psssup.nStatusUpdate);
515  break;
516  }
517  }
518 }
519 
520 //
521 // After we receive the finalized transaction from the Masternode, we must
522 // check it to make sure it's what we want, then sign it if we agree.
523 // If we refuse to sign, it's possible we'll be charged collateral
524 //
525 bool CPrivateSendClientSession::SignFinalTransaction(const CTransaction& finalTransactionNew, CNode* pnode, CConnman& connman)
526 {
528 
529  if (fMasternodeMode || pnode == nullptr) return false;
530  if (!mixingMasternode) return false;
531 
532  finalMutableTransaction = finalTransactionNew;
533  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- finalMutableTransaction=%s", __func__, finalMutableTransaction.ToString());
534 
535  // STEP 1: check final transaction general rules
536 
537  // Make sure it's BIP69 compliant
540 
541  if (finalMutableTransaction.GetHash() != finalTransactionNew.GetHash()) {
542  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- ERROR! Masternode %s is not BIP69 compliant!\n", __func__, mixingMasternode->proTxHash.ToString());
543  UnlockCoins();
545  SetNull();
546  return false;
547  }
548 
549  // Make sure all inputs/outputs are valid
550  PoolMessage nMessageID{MSG_NOERR};
552  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- ERROR! IsValidInOuts() failed: %s\n", __func__, CPrivateSend::GetMessageByID(nMessageID));
553  UnlockCoins();
555  SetNull();
556  return false;
557  }
558 
559  // STEP 2: make sure our own inputs/outputs are present, otherwise refuse to sign
560 
561  std::vector<CTxIn> sigs;
562 
563  for (const auto& entry : vecEntries) {
564  // Check that the final transaction has all our outputs
565  for (const auto& txout : entry.vecTxOut) {
566  bool fFound = false;
567  for (const auto& txoutFinal : finalMutableTransaction.vout) {
568  if (txoutFinal == txout) {
569  fFound = true;
570  break;
571  }
572  }
573  if (!fFound) {
574  // Something went wrong and we'll refuse to sign. It's possible we'll be charged collateral. But that's
575  // better than signing if the transaction doesn't look like what we wanted.
576  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- an output is missing, refusing to sign! txout=%s\n", __func__, txout.ToString());
577  UnlockCoins();
579  SetNull();
580  return false;
581  }
582  }
583 
584  for (const auto& txdsin : entry.vecTxDSIn) {
585  /* Sign my transaction and all outputs */
586  int nMyInputIndex = -1;
587  CScript prevPubKey = CScript();
588 
589  for (unsigned int i = 0; i < finalMutableTransaction.vin.size(); i++) {
590  if (finalMutableTransaction.vin[i] == txdsin) {
591  nMyInputIndex = i;
592  prevPubKey = txdsin.prevPubKey;
593  break;
594  }
595  }
596 
597  if (nMyInputIndex == -1) {
598  // Can't find one of my own inputs, refuse to sign. It's possible we'll be charged collateral. But that's
599  // better than signing if the transaction doesn't look like what we wanted.
600  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- missing input! txdsin=%s\n", __func__, txdsin.ToString());
601  UnlockCoins();
603  SetNull();
604  return false;
605  }
606 
607  const CKeyStore& keystore = *GetWallets()[0];
608 
609  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- Signing my input %i\n", __func__, nMyInputIndex);
610  // 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)
611  if (!SignSignature(keystore, prevPubKey, finalMutableTransaction, nMyInputIndex, 0, int(SIGHASH_ALL | SIGHASH_ANYONECANPAY))) { // changes scriptSig
612  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- Unable to sign my own transaction!\n", __func__);
613  // not sure what to do here, it will timeout...?
614  }
615 
616  sigs.push_back(finalMutableTransaction.vin[nMyInputIndex]);
617  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- nMyInputIndex: %d, sigs.size(): %d, scriptSig=%s\n",
618  __func__, nMyInputIndex, (int)sigs.size(), ScriptToAsmStr(finalMutableTransaction.vin[nMyInputIndex].scriptSig));
619  }
620  }
621 
622  if (sigs.empty()) {
623  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- can't sign anything!\n", __func__);
624  UnlockCoins();
626  SetNull();
627 
628  return false;
629  }
630 
631  // push all of our signatures to the Masternode
632  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- pushing sigs to the masternode, finalMutableTransaction=%s", __func__, finalMutableTransaction.ToString());
633  CNetMsgMaker msgMaker(pnode->GetSendVersion());
634  connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSSIGNFINALTX, sigs));
637 
638  return true;
639 }
640 
641 // mixing transaction was completed (failed or successful)
643 {
644  if (fMasternodeMode) return;
645 
646  if (nMessageID == MSG_SUCCESS) {
647  LogPrint(BCLog::PRIVATESEND, "CompletedTransaction -- success\n");
650  } else {
651  LogPrint(BCLog::PRIVATESEND, "CompletedTransaction -- error\n");
653  }
654  UnlockCoins();
655  SetNull();
657 }
658 
660 {
661  if (fMasternodeMode) return;
663 }
664 
666 {
667  if (!masternodeSync.IsBlockchainSynced()) return true;
668 
669  if (fPrivateSendMultiSession) return false;
670 
672 }
673 
675 {
676  if (!fEnablePrivateSend || !fPrivateSendRunning) return false;
677 
678  switch (nWalletBackups) {
679  case 0:
680  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Automatic backups disabled, no mixing available.\n");
681  strAutoDenomResult = _("Automatic backups disabled") + ", " + _("no mixing available.");
682  fPrivateSendRunning = false; // stop mixing
683  GetWallets()[0]->nKeysLeftSinceAutoBackup = 0; // no backup, no "keys since last backup"
684  return false;
685  case -1:
686  // Automatic backup failed, nothing else we can do until user fixes the issue manually.
687  // There is no way to bring user attention in daemon mode so we just update status and
688  // keep spamming if debug is on.
689  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- ERROR! Failed to create automatic backup.\n");
690  strAutoDenomResult = _("ERROR! Failed to create automatic backup") + ", " + _("see debug.log for details.");
691  return false;
692  case -2:
693  // We were able to create automatic backup but keypool was not replenished because wallet is locked.
694  // There is no way to bring user attention in daemon mode so we just update status and
695  // keep spamming if debug is on.
696  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- WARNING! Failed to create replenish keypool, please unlock your wallet to do so.\n");
697  strAutoDenomResult = _("WARNING! Failed to replenish keypool, please unlock your wallet to do so.") + ", " + _("see debug.log for details.");
698  return false;
699  }
700 
701  if (GetWallets()[0]->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_STOP) {
702  // We should never get here via mixing itself but probably something else is still actively using keypool
703  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d, no mixing available.\n", GetWallets()[0]->nKeysLeftSinceAutoBackup);
704  strAutoDenomResult = strprintf(_("Very low number of keys left: %d") + ", " + _("no mixing available."), GetWallets()[0]->nKeysLeftSinceAutoBackup);
705  // It's getting really dangerous, stop mixing
706  fPrivateSendRunning = false;
707  return false;
708  } else if (GetWallets()[0]->nKeysLeftSinceAutoBackup < PRIVATESEND_KEYS_THRESHOLD_WARNING) {
709  // Low number of keys left but it's still more or less safe to continue
710  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Very low number of keys left: %d\n", GetWallets()[0]->nKeysLeftSinceAutoBackup);
711  strAutoDenomResult = strprintf(_("Very low number of keys left: %d"), GetWallets()[0]->nKeysLeftSinceAutoBackup);
712 
713  if (fCreateAutoBackups) {
714  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Trying to create new backup.\n");
715  std::string warningString;
716  std::string errorString;
717 
718  if (!GetWallets()[0]->AutoBackupWallet("", warningString, errorString)) {
719  if (!warningString.empty()) {
720  // There were some issues saving backup but yet more or less safe to continue
721  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- WARNING! Something went wrong on automatic backup: %s\n", warningString);
722  }
723  if (!errorString.empty()) {
724  // Things are really broken
725  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- ERROR! Failed to create automatic backup: %s\n", errorString);
726  strAutoDenomResult = strprintf(_("ERROR! Failed to create automatic backup") + ": %s", errorString);
727  return false;
728  }
729  }
730  } else {
731  // Wait for something else (e.g. GUI action) to create automatic backup for us
732  return false;
733  }
734  }
735 
736  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::CheckAutomaticBackup -- Keys left since latest backup: %d\n", GetWallets()[0]->nKeysLeftSinceAutoBackup);
737 
738  return true;
739 }
740 
741 //
742 // Passively run mixing in the background to mix funds based on the given configuration.
743 //
745 {
746  if (fMasternodeMode) return false; // no client-side mixing on masternodes
747  if (nState != POOL_STATE_IDLE) return false;
748 
750  strAutoDenomResult = _("Can't mix while sync in progress.");
751  return false;
752  }
753 
755 
756  CAmount nBalanceNeedsAnonymized;
757 
758  {
760  LOCK(GetWallets()[0]->cs_wallet);
761 
762  if (!fDryRun && GetWallets()[0]->IsLocked(true)) {
763  strAutoDenomResult = _("Wallet is locked.");
764  return false;
765  }
766 
767  if (GetEntriesCount() > 0) {
768  strAutoDenomResult = _("Mixing in progress...");
769  return false;
770  }
771 
772  TRY_LOCK(cs_privatesend, lockDS);
773  if (!lockDS) {
774  strAutoDenomResult = _("Lock is already in place.");
775  return false;
776  }
777 
778  if (deterministicMNManager->GetListAtChainTip().GetValidMNsCount() == 0 &&
780  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- No Masternodes detected\n");
781  strAutoDenomResult = _("No Masternodes detected.");
782  return false;
783  }
784 
785  // check if there is anything left to do
786  CAmount nBalanceAnonymized = GetWallets()[0]->GetAnonymizedBalance();
787  nBalanceNeedsAnonymized = privateSendClient.nPrivateSendAmount*COIN - nBalanceAnonymized;
788 
789  if (nBalanceNeedsAnonymized < 0) {
790  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- Nothing to do\n");
791  // nothing to do, just keep it in idle mode
792  return false;
793  }
794 
796 
797  // if there are no confirmed DS collateral inputs yet
798  if (!GetWallets()[0]->HasCollateralInputs()) {
799  // should have some additional amount for them
801  }
802 
803  // including denoms but applying some restrictions
804  CAmount nBalanceAnonymizable = GetWallets()[0]->GetAnonymizableBalance();
805 
806  // mixable balance is way too small
807  if (nBalanceAnonymizable < nValueMin) {
808  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- Not enough funds to mix\n");
809  strAutoDenomResult = _("Not enough funds to mix.");
810  return false;
811  }
812 
813  // excluding denoms
814  CAmount nBalanceAnonimizableNonDenom = GetWallets()[0]->GetAnonymizableBalance(true);
815  // denoms
816  CAmount nBalanceDenominatedConf = GetWallets()[0]->GetDenominatedBalance();
817  CAmount nBalanceDenominatedUnconf = GetWallets()[0]->GetDenominatedBalance(true);
818  CAmount nBalanceDenominated = nBalanceDenominatedConf + nBalanceDenominatedUnconf;
819  CAmount nBalanceToDenominate = privateSendClient.nPrivateSendAmount * COIN - nBalanceDenominated;
820 
821  // adjust nBalanceNeedsAnonymized to consume final denom
822  if (nBalanceDenominated - nBalanceAnonymized > nBalanceNeedsAnonymized) {
824  CAmount nAdditionalDenom{0};
825  for (const auto& denom : denoms) {
826  if (nBalanceNeedsAnonymized < denom) {
827  nAdditionalDenom = denom;
828  } else {
829  break;
830  }
831  }
832  nBalanceNeedsAnonymized += nAdditionalDenom;
833  }
834 
835  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- current stats:\n"
836  " nValueMin: %s\n"
837  " nBalanceAnonymizable: %s\n"
838  " nBalanceAnonymized: %s\n"
839  " nBalanceNeedsAnonymized: %s\n"
840  " nBalanceAnonimizableNonDenom: %s\n"
841  " nBalanceDenominatedConf: %s\n"
842  " nBalanceDenominatedUnconf: %s\n"
843  " nBalanceDenominated: %s\n"
844  " nBalanceToDenominate: %s\n",
845  FormatMoney(nValueMin),
846  FormatMoney(nBalanceAnonymizable),
847  FormatMoney(nBalanceAnonymized),
848  FormatMoney(nBalanceNeedsAnonymized),
849  FormatMoney(nBalanceAnonimizableNonDenom),
850  FormatMoney(nBalanceDenominatedConf),
851  FormatMoney(nBalanceDenominatedUnconf),
852  FormatMoney(nBalanceDenominated),
853  FormatMoney(nBalanceToDenominate)
854  );
855 
856  if (fDryRun) return true;
857 
858  // Check if we have should create more denominated inputs i.e.
859  // there are funds to denominate and denominated balance does not exceed
860  // max amount to mix yet.
861  if (nBalanceAnonimizableNonDenom >= nValueMin + CPrivateSend::GetCollateralAmount() && nBalanceToDenominate > 0) {
862  CreateDenominated(nBalanceToDenominate);
863  }
864 
865  //check if we have the collateral sized inputs
866  if (!GetWallets()[0]->HasCollateralInputs()) {
867  return !GetWallets()[0]->HasCollateralInputs(false) && MakeCollateralAmounts();
868  }
869 
870  if (nSessionID) {
871  strAutoDenomResult = _("Mixing in progress...");
872  return false;
873  }
874 
875  // Initial phase, find a Masternode
876  // Clean if there is anything left from previous session
877  UnlockCoins();
879  SetNull();
880 
881  // should be no unconfirmed denoms in non-multi-session mode
882  if (!privateSendClient.fPrivateSendMultiSession && nBalanceDenominatedUnconf > 0) {
883  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- Found unconfirmed denominated outputs, will wait till they confirm to continue.\n");
884  strAutoDenomResult = _("Found unconfirmed denominated outputs, will wait till they confirm to continue.");
885  return false;
886  }
887 
888  //check our collateral and create new if needed
889  std::string strReason;
891  if (!GetWallets()[0]->CreateCollateralTransaction(txMyCollateral, strReason)) {
892  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- create collateral error:%s\n", strReason);
893  return false;
894  }
895  } else {
897  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- invalid collateral, recreating...\n");
898  if (!GetWallets()[0]->CreateCollateralTransaction(txMyCollateral, strReason)) {
899  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::DoAutomaticDenominating -- create collateral error: %s\n", strReason);
900  return false;
901  }
902  }
903  }
904  // lock the funds we're going to use for our collateral
905  for (const auto& txin : txMyCollateral.vin) {
906  GetWallets()[0]->LockCoin(txin.prevout);
907  vecOutPointLocked.push_back(txin.prevout);
908  }
909  } // LOCK2(cs_main, GetWallets()[0]->cs_wallet);
910 
911  // Always attempt to join an existing queue
912  if (JoinExistingQueue(nBalanceNeedsAnonymized, connman)) {
913  return true;
914  }
915 
916  // If we were unable to find/join an existing queue then start a new one.
917  if (StartNewQueue(nBalanceNeedsAnonymized, connman)) return true;
918 
919  strAutoDenomResult = _("No compatible Masternode found.");
920  return false;
921 }
922 
924 {
925  if (fMasternodeMode) return false; // no client-side mixing on masternodes
926  if (!fEnablePrivateSend || !fPrivateSendRunning) return false;
927 
929  strAutoDenomResult = _("Can't mix while sync in progress.");
930  return false;
931  }
932 
933  if (!fDryRun && GetWallets()[0]->IsLocked(true)) {
934  strAutoDenomResult = _("Wallet is locked.");
935  return false;
936  }
937 
938  int nMnCountEnabled = deterministicMNManager->GetListAtChainTip().GetValidMNsCount();
939 
940  // If we've used 90% of the Masternode list then drop the oldest first ~30%
941  int nThreshold_high = nMnCountEnabled * 0.9;
942  int nThreshold_low = nThreshold_high * 0.7;
943  LogPrint(BCLog::PRIVATESEND, "Checking vecMasternodesUsed: size: %d, threshold: %d\n", (int)vecMasternodesUsed.size(), nThreshold_high);
944 
945  if ((int)vecMasternodesUsed.size() > nThreshold_high) {
946  vecMasternodesUsed.erase(vecMasternodesUsed.begin(), vecMasternodesUsed.begin() + vecMasternodesUsed.size() - nThreshold_low);
947  LogPrint(BCLog::PRIVATESEND, " vecMasternodesUsed: new size: %d, threshold: %d\n", (int)vecMasternodesUsed.size(), nThreshold_high);
948  }
949 
951  bool fResult = true;
952  if ((int)deqSessions.size() < nPrivateSendSessions) {
953  deqSessions.emplace_back();
954  }
955  for (auto& session : deqSessions) {
956  if (!CheckAutomaticBackup()) return false;
957 
958  if (WaitForAnotherBlock()) {
959  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::DoAutomaticDenominating -- Last successful PrivateSend action was too recent\n");
960  strAutoDenomResult = _("Last successful PrivateSend action was too recent.");
961  return false;
962  }
963 
964  fResult &= session.DoAutomaticDenominating(connman, fDryRun);
965  }
966 
967  return fResult;
968 }
969 
971 {
972  vecMasternodesUsed.push_back(outpointMn);
973 }
974 
976 {
977  auto mnList = deterministicMNManager->GetListAtChainTip();
978 
979  int nCountEnabled = mnList.GetValidMNsCount();
980  int nCountNotExcluded = nCountEnabled - vecMasternodesUsed.size();
981 
982  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::%s -- %d enabled masternodes, %d masternodes to choose from\n", __func__, nCountEnabled, nCountNotExcluded);
983  if(nCountNotExcluded < 1) {
984  return nullptr;
985  }
986 
987  // fill a vector
988  std::vector<CDeterministicMNCPtr> vpMasternodesShuffled;
989  vpMasternodesShuffled.reserve((size_t)nCountEnabled);
990  mnList.ForEachMN(true, [&](const CDeterministicMNCPtr& dmn) {
991  vpMasternodesShuffled.emplace_back(dmn);
992  });
993 
994  FastRandomContext insecure_rand;
995  // shuffle pointers
996  std::random_shuffle(vpMasternodesShuffled.begin(), vpMasternodesShuffled.end(), insecure_rand);
997 
998  std::set<COutPoint> excludeSet(vecMasternodesUsed.begin(), vecMasternodesUsed.end());
999 
1000  // loop through
1001  for (const auto& dmn : vpMasternodesShuffled) {
1002  if (excludeSet.count(dmn->collateralOutpoint)) {
1003  continue;
1004  }
1005 
1006  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::%s -- found, masternode=%s\n", __func__, dmn->collateralOutpoint.ToStringShort());
1007  return dmn;
1008  }
1009 
1010  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::%s -- failed\n", __func__);
1011  return nullptr;
1012 }
1013 
1014 bool CPrivateSendClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman)
1015 {
1017 
1018  auto mnList = deterministicMNManager->GetListAtChainTip();
1019 
1020  // Look through the queues and see if anything matches
1021  CPrivateSendQueue dsq;
1022  while (privateSendClient.GetQueueItemAndTry(dsq)) {
1023  auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint);
1024 
1025  if (!dmn) {
1026  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::JoinExistingQueue -- dsq masternode is not in masternode list, masternode=%s\n", dsq.masternodeOutpoint.ToStringShort());
1027  continue;
1028  }
1029 
1030  // skip next mn payments winners
1031  if (dmn->pdmnState->nLastPaidHeight + mnList.GetValidMNsCount() < mnList.GetHeight() + 8) {
1032  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::JoinExistingQueue -- skipping winner, masternode=%s\n", dmn->proTxHash.ToString());
1033  continue;
1034  }
1035 
1036  // mixing rate limit i.e. nLastDsq check should already pass in DSQUEUE ProcessMessage
1037  // in order for dsq to get into vecPrivateSendQueue, so we should be safe to mix already,
1038  // no need for additional verification here
1039 
1040  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::JoinExistingQueue -- trying queue: %s\n", dsq.ToString());
1041 
1042  std::vector<std::pair<CTxDSIn, CTxOut> > vecPSInOutPairsTmp;
1043 
1044  // Try to match their denominations if possible, select exact number of denominations
1045  if (!GetWallets()[0]->SelectPSInOutPairsByDenominations(dsq.nDenom, nBalanceNeedsAnonymized, vecPSInOutPairsTmp)) {
1046  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::JoinExistingQueue -- Couldn't match denomination %d (%s)\n", dsq.nDenom, CPrivateSend::DenominationToString(dsq.nDenom));
1047  continue;
1048  }
1049 
1051 
1052  if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->addr)) {
1053  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::JoinExistingQueue -- skipping masternode connection, addr=%s\n", dmn->pdmnState->addr.ToString());
1054  continue;
1055  }
1056 
1057  nSessionDenom = dsq.nDenom;
1058  mixingMasternode = dmn;
1060  connman.AddPendingMasternode(dmn->proTxHash);
1061  // TODO: add new state POOL_STATE_CONNECTING and bump MIN_PRIVATESEND_PEER_PROTO_VERSION
1064  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::JoinExistingQueue -- pending connection (from queue): nSessionDenom: %d (%s), addr=%s\n",
1065  nSessionDenom, CPrivateSend::DenominationToString(nSessionDenom), dmn->pdmnState->addr.ToString());
1066  strAutoDenomResult = _("Trying to connect...");
1067  return true;
1068  }
1069  strAutoDenomResult = _("Failed to find mixing queue to join");
1070  return false;
1071 }
1072 
1073 bool CPrivateSendClientSession::StartNewQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman)
1074 {
1076  if (nBalanceNeedsAnonymized <= 0) return false;
1077 
1078  int nTries = 0;
1079  auto mnList = deterministicMNManager->GetListAtChainTip();
1080  int nMnCount = mnList.GetValidMNsCount();
1081 
1082  // find available denominated amounts
1083  std::set<CAmount> setAmounts;
1084  if (!GetWallets()[0]->SelectDenominatedAmounts(nBalanceNeedsAnonymized, setAmounts)) {
1085  // this should never happen
1086  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- Can't mix: no compatible inputs found!\n");
1087  strAutoDenomResult = _("Can't mix: no compatible inputs found!");
1088  return false;
1089  }
1090 
1091  // otherwise, try one randomly
1092  while (nTries < 10) {
1094 
1095  if (!dmn) {
1096  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- Can't find random masternode!\n");
1097  strAutoDenomResult = _("Can't find random Masternode.");
1098  return false;
1099  }
1100 
1101  privateSendClient.AddUsedMasternode(dmn->collateralOutpoint);
1102 
1103  // skip next mn payments winners
1104  if (dmn->pdmnState->nLastPaidHeight + nMnCount < mnList.GetHeight() + 8) {
1105  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- skipping winner, masternode=%s\n", dmn->proTxHash.ToString());
1106  nTries++;
1107  continue;
1108  }
1109 
1110  int64_t nLastDsq = mmetaman.GetMetaInfo(dmn->proTxHash)->GetLastDsq();
1111  int64_t nDsqThreshold = mmetaman.GetDsqThreshold(dmn->proTxHash, nMnCount);
1112  if (nLastDsq != 0 && nDsqThreshold > mmetaman.GetDsqCount()) {
1113  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- Too early to mix on this masternode!"
1114  " masternode=%s addr=%s nLastDsq=%d nDsqThreshold=%d nDsqCount=%d\n",
1115  dmn->proTxHash.ToString(), dmn->pdmnState->addr.ToString(), nLastDsq,
1116  nDsqThreshold, mmetaman.GetDsqCount());
1117  nTries++;
1118  continue;
1119  }
1120 
1121  if (connman.IsMasternodeOrDisconnectRequested(dmn->pdmnState->addr)) {
1122  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- skipping masternode connection, addr=%s\n", dmn->pdmnState->addr.ToString());
1123  nTries++;
1124  continue;
1125  }
1126 
1127  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- attempt %d connection to Masternode %s\n", nTries, dmn->pdmnState->addr.ToString());
1128 
1129  // try to get a single random denom out of setAmounts
1130  while (nSessionDenom == 0) {
1131  for (auto it = setAmounts.rbegin(); it != setAmounts.rend(); ++it) {
1132  if (setAmounts.size() > 1 && GetRandInt(2)) continue;
1134  break;
1135  }
1136  }
1137 
1138  mixingMasternode = dmn;
1139  connman.AddPendingMasternode(dmn->proTxHash);
1141  // TODO: add new state POOL_STATE_CONNECTING and bump MIN_PRIVATESEND_PEER_PROTO_VERSION
1144  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::StartNewQueue -- pending connection, nSessionDenom: %d (%s), addr=%s\n",
1145  nSessionDenom, CPrivateSend::DenominationToString(nSessionDenom), dmn->pdmnState->addr.ToString());
1146  strAutoDenomResult = _("Trying to connect...");
1147  return true;
1148  }
1149  strAutoDenomResult = _("Failed to start a new mixing queue");
1150  return false;
1151 }
1152 
1154 {
1155  if (!pendingDsaRequest) return false;
1156 
1157  bool fDone = connman.ForNode(pendingDsaRequest.GetAddr(), [&](CNode* pnode) {
1158  LogPrint(BCLog::PRIVATESEND, "-- processing dsa queue for addr=%s\n", pnode->addr.ToString());
1160  // TODO: this vvvv should be here after new state POOL_STATE_CONNECTING is added and MIN_PRIVATESEND_PEER_PROTO_VERSION is bumped
1161  // SetState(POOL_STATE_QUEUE);
1162  CNetMsgMaker msgMaker(pnode->GetSendVersion());
1163  connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSACCEPT, pendingDsaRequest.GetDSA()));
1164  return true;
1165  });
1166 
1167  if (fDone) {
1169  } else if (pendingDsaRequest.IsExpired()) {
1170  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- failed to connect to %s\n", __func__, pendingDsaRequest.GetAddr().ToString());
1171  SetNull();
1172  }
1173 
1174  return fDone;
1175 }
1176 
1178 {
1180  for (auto& session : deqSessions) {
1181  if (session.ProcessPendingDsaRequest(connman)) {
1182  strAutoDenomResult = _("Mixing in progress...");
1183  }
1184  }
1185 }
1186 
1188 {
1189  LOCK2(cs_main, mempool.cs);
1190  LOCK(GetWallets()[0]->cs_wallet);
1191 
1192  std::string strError;
1193  std::vector<std::pair<CTxDSIn, CTxOut> > vecPSInOutPairs, vecPSInOutPairsTmp;
1194 
1195  if (!SelectDenominate(strError, vecPSInOutPairs)) {
1196  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SubmitDenominate -- SelectDenominate failed, error: %s\n", strError);
1197  return false;
1198  }
1199 
1200  std::vector<std::pair<int, size_t> > vecInputsByRounds;
1201 
1203  if (PrepareDenominate(i, i, strError, vecPSInOutPairs, vecPSInOutPairsTmp, true)) {
1204  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", i);
1205  vecInputsByRounds.emplace_back(i, vecPSInOutPairsTmp.size());
1206  } else {
1207  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, error: %s\n", i, strError);
1208  }
1209  }
1210 
1211  // more inputs first, for equal input count prefer the one with less rounds
1212  std::sort(vecInputsByRounds.begin(), vecInputsByRounds.end(), [](const auto& a, const auto& b) {
1213  return a.second > b.second || (a.second == b.second && a.first < b.first);
1214  });
1215 
1216  LogPrint(BCLog::PRIVATESEND, "vecInputsByRounds for denom %d\n", nSessionDenom);
1217  for (const auto& pair : vecInputsByRounds) {
1218  LogPrint(BCLog::PRIVATESEND, "vecInputsByRounds: rounds: %d, inputs: %d\n", pair.first, pair.second);
1219  }
1220 
1221  int nRounds = vecInputsByRounds.begin()->first;
1222  if (PrepareDenominate(nRounds, nRounds, strError, vecPSInOutPairs, vecPSInOutPairsTmp)) {
1223  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for %d rounds, success\n", nRounds);
1224  return SendDenominate(vecPSInOutPairsTmp, connman);
1225  }
1226 
1227  // We failed? That's strange but let's just make final attempt and try to mix everything
1228  if (PrepareDenominate(0, privateSendClient.nPrivateSendRounds - 1, strError, vecPSInOutPairs, vecPSInOutPairsTmp)) {
1229  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for all rounds, success\n");
1230  return SendDenominate(vecPSInOutPairsTmp, connman);
1231  }
1232 
1233  // Should never actually get here but just in case
1234  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SubmitDenominate -- Running PrivateSend denominate for all rounds, error: %s\n", strError);
1235  strAutoDenomResult = strError;
1236  return false;
1237 }
1238 
1239 bool CPrivateSendClientSession::SelectDenominate(std::string& strErrorRet, std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsRet)
1240 {
1242 
1243  if (GetWallets()[0]->IsLocked(true)) {
1244  strErrorRet = "Wallet locked, unable to create transaction!";
1245  return false;
1246  }
1247 
1248  if (GetEntriesCount() > 0) {
1249  strErrorRet = "Already have pending entries in the PrivateSend pool";
1250  return false;
1251  }
1252 
1253  vecPSInOutPairsRet.clear();
1254 
1255  bool fSelected = GetWallets()[0]->SelectPSInOutPairsByDenominations(nSessionDenom, CPrivateSend::GetMaxPoolAmount(), vecPSInOutPairsRet);
1256  if (!fSelected) {
1257  strErrorRet = "Can't select current denominated inputs";
1258  return false;
1259  }
1260 
1261  return true;
1262 }
1263 
1264 bool CPrivateSendClientSession::PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, const std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsIn, std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsRet, bool fDryRun)
1265 {
1267  AssertLockHeld(GetWallets()[0]->cs_wallet);
1268 
1270  strErrorRet = "Incorrect session denom";
1271  return false;
1272  }
1274 
1275  // NOTE: No need to randomize order of inputs because they were
1276  // initially shuffled in CWallet::SelectPSInOutPairsByDenominations already.
1277  int nSteps{0};
1278  vecPSInOutPairsRet.clear();
1279 
1280  // Try to add up to PRIVATESEND_ENTRY_MAX_SIZE of every needed denomination
1281  for (const auto& pair : vecPSInOutPairsIn) {
1282  if (nSteps >= PRIVATESEND_ENTRY_MAX_SIZE) break;
1283  if (pair.second.nRounds < nMinRounds || pair.second.nRounds > nMaxRounds) continue;
1284  if (pair.second.nValue != nDenomAmount) continue;
1285 
1286  CScript scriptDenom;
1287  if (fDryRun) {
1288  scriptDenom = CScript();
1289  } else {
1290  // randomly skip some inputs when we have at least one of the same denom already
1291  // TODO: make it adjustable via options/cmd-line params
1292  if (nSteps >= 1 && GetRandInt(5) == 0) {
1293  // still count it as a step to randomize number of inputs
1294  // if we have more than (or exactly) PRIVATESEND_ENTRY_MAX_SIZE of them
1295  ++nSteps;
1296  continue;
1297  }
1298  scriptDenom = keyHolderStorage.AddKey(GetWallets()[0]);
1299  }
1300  vecPSInOutPairsRet.emplace_back(pair.first, CTxOut(nDenomAmount, scriptDenom));
1301  // step is complete
1302  ++nSteps;
1303  }
1304 
1305  if (vecPSInOutPairsRet.empty()) {
1307  strErrorRet = "Can't prepare current denominated outputs";
1308  return false;
1309  }
1310 
1311  if (fDryRun) {
1312  return true;
1313  }
1314 
1315  for (const auto& pair : vecPSInOutPairsRet) {
1316  GetWallets()[0]->LockCoin(pair.first.prevout);
1317  vecOutPointLocked.push_back(pair.first.prevout);
1318  }
1319 
1320  return true;
1321 }
1322 
1323 // Create collaterals by looping through inputs grouped by addresses
1325 {
1327 
1328  LOCK2(cs_main, mempool.cs);
1329  LOCK(GetWallets()[0]->cs_wallet);
1330 
1331  // NOTE: We do not allow txes larger than 100kB, so we have to limit number of inputs here.
1332  // We still want to consume a lot of inputs to avoid creating only smaller denoms though.
1333  // Knowing that each CTxIn is at least 148b big, 400 inputs should take 400 x ~148b = ~60kB.
1334  // This still leaves more than enough room for another data of typical MakeCollateralAmounts tx.
1335  std::vector<CompactTallyItem> vecTally;
1336  if (!GetWallets()[0]->SelectCoinsGroupedByAddresses(vecTally, false, false, true, 400)) {
1337  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- SelectCoinsGroupedByAddresses can't find any inputs!\n");
1338  return false;
1339  }
1340 
1341  // Start from smallest balances first to consume tiny amounts and cleanup UTXO a bit
1342  std::sort(vecTally.begin(), vecTally.end(), [](const CompactTallyItem& a, const CompactTallyItem& b) {
1343  return a.nAmount < b.nAmount;
1344  });
1345 
1346  // First try to use only non-denominated funds
1347  for (const auto& item : vecTally) {
1348  if (!MakeCollateralAmounts(item, false)) continue;
1349  return true;
1350  }
1351 
1352  // There should be at least some denominated funds we should be able to break in pieces to continue mixing
1353  for (const auto& item : vecTally) {
1354  if (!MakeCollateralAmounts(item, true)) continue;
1355  return true;
1356  }
1357 
1358  // If we got here then something is terribly broken actually
1359  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::MakeCollateralAmounts -- ERROR: Can't make collaterals!\n");
1360  return false;
1361 }
1362 
1363 // Split up large inputs or create fee sized inputs
1364 bool CPrivateSendClientSession::MakeCollateralAmounts(const CompactTallyItem& tallyItem, bool fTryDenominated)
1365 {
1368  AssertLockHeld(GetWallets()[0]->cs_wallet);
1369 
1371 
1372  // Denominated input is always a single one, so we can check its amount directly and return early
1373  if (!fTryDenominated && tallyItem.vecOutPoints.size() == 1 && CPrivateSend::IsDenominatedAmount(tallyItem.nAmount)) {
1374  return false;
1375  }
1376 
1377  // Skip single inputs that can be used as collaterals already
1378  if (tallyItem.vecOutPoints.size() == 1 && CPrivateSend::IsCollateralAmount(tallyItem.nAmount)) {
1379  return false;
1380  }
1381 
1382  CTransactionBuilder txBuilder(GetWallets()[0], tallyItem);
1383 
1384  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- Start %s\n", __func__, txBuilder.ToString());
1385 
1386  // Skip way too tiny amounts. Smallest we want is minimum collateral amount in a one output tx
1388  return false;
1389  }
1390 
1391  int nCase{0}; // Just for debug logs
1392  if (txBuilder.CouldAddOutputs({CPrivateSend::GetMaxCollateralAmount(), CPrivateSend::GetCollateralAmount()})) {
1393  nCase = 1;
1394  // <case1>, see TransactionRecord::decomposeTransaction
1395  // Out1 == CPrivateSend::GetMaxCollateralAmount()
1396  // Out2 >= CPrivateSend::GetCollateralAmount()
1397 
1399  // Note, here we first add a zero amount output to get the remainder after all fees and then assign it
1400  CTransactionBuilderOutput* out = txBuilder.AddOutput();
1401  CAmount nAmountLeft = txBuilder.GetAmountLeft();
1402  // If remainder is denominated add one duff to the fee
1403  out->UpdateAmount(CPrivateSend::IsDenominatedAmount(nAmountLeft) ? nAmountLeft - 1 : nAmountLeft);
1404 
1405  } else if (txBuilder.CouldAddOutputs({CPrivateSend::GetCollateralAmount(), CPrivateSend::GetCollateralAmount()})) {
1406  nCase = 2;
1407  // <case2>, see TransactionRecord::decomposeTransaction
1408  // Out1 CPrivateSend::IsCollateralAmount()
1409  // Out2 CPrivateSend::IsCollateralAmount()
1410 
1411  // First add two outputs to get the available value after all fees
1412  CTransactionBuilderOutput* out1 = txBuilder.AddOutput();
1413  CTransactionBuilderOutput* out2 = txBuilder.AddOutput();
1414 
1415  // Create two equal outputs from the available value. This adds one duff to the fee if txBuilder.GetAmountLeft() is odd.
1416  CAmount nAmountOutputs = txBuilder.GetAmountLeft() / 2;
1417 
1418  assert(CPrivateSend::IsCollateralAmount(nAmountOutputs));
1419 
1420  out1->UpdateAmount(nAmountOutputs);
1421  out2->UpdateAmount(nAmountOutputs);
1422 
1423  } else { // still at least possible to add one CPrivateSend::GetCollateralAmount() output
1424  nCase = 3;
1425  // <case3>, see TransactionRecord::decomposeTransaction
1426  // Out1 CPrivateSend::IsCollateralAmount()
1427  // Out2 Skipped
1428  CTransactionBuilderOutput* out = txBuilder.AddOutput();
1429  out->UpdateAmount(txBuilder.GetAmountLeft());
1430 
1432  }
1433 
1434  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- Done with case %d: %s\n", __func__, nCase, txBuilder.ToString());
1435 
1436  assert(txBuilder.IsDust(txBuilder.GetAmountLeft()));
1437 
1438  std::string strResult;
1439  if (!txBuilder.Commit(strResult)) {
1440  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- Commit failed: %s\n", __func__, strResult);
1441  return false;
1442  }
1443 
1445 
1446  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- txid: %s\n", __func__, strResult);
1447 
1448  return true;
1449 }
1450 
1451 // Create denominations by looping through inputs grouped by addresses
1453 {
1455 
1456  LOCK2(cs_main, mempool.cs);
1457  LOCK(GetWallets()[0]->cs_wallet);
1458 
1459  // NOTE: We do not allow txes larger than 100kB, so we have to limit number of inputs here.
1460  // We still want to consume a lot of inputs to avoid creating only smaller denoms though.
1461  // Knowing that each CTxIn is at least 148b big, 400 inputs should take 400 x ~148b = ~60kB.
1462  // This still leaves more than enough room for another data of typical CreateDenominated tx.
1463  std::vector<CompactTallyItem> vecTally;
1464  if (!GetWallets()[0]->SelectCoinsGroupedByAddresses(vecTally, true, true, true, 400)) {
1465  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- SelectCoinsGroupedByAddresses can't find any inputs!\n");
1466  return false;
1467  }
1468 
1469  // Start from largest balances first to speed things up by creating txes with larger/largest denoms included
1470  std::sort(vecTally.begin(), vecTally.end(), [](const CompactTallyItem& a, const CompactTallyItem& b) {
1471  return a.nAmount > b.nAmount;
1472  });
1473 
1474  bool fCreateMixingCollaterals = !GetWallets()[0]->HasCollateralInputs();
1475 
1476  for (const auto& item : vecTally) {
1477  if (!CreateDenominated(nBalanceToDenominate, item, fCreateMixingCollaterals)) continue;
1478  return true;
1479  }
1480 
1481  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::CreateDenominated -- failed!\n");
1482  return false;
1483 }
1484 
1485 // Create denominations
1486 bool CPrivateSendClientSession::CreateDenominated(CAmount nBalanceToDenominate, const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals)
1487 {
1490  AssertLockHeld(GetWallets()[0]->cs_wallet);
1491 
1493 
1494  // denominated input is always a single one, so we can check its amount directly and return early
1495  if (tallyItem.vecOutPoints.size() == 1 && CPrivateSend::IsDenominatedAmount(tallyItem.nAmount)) {
1496  return false;
1497  }
1498 
1499  CTransactionBuilder txBuilder(GetWallets()[0], tallyItem);
1500 
1501  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- Start %s\n", __func__, txBuilder.ToString());
1502 
1503  // ****** Add an output for mixing collaterals ************ /
1504 
1505  if (fCreateMixingCollaterals && !txBuilder.AddOutput(CPrivateSend::GetMaxCollateralAmount())) {
1506  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- Failed to add collateral output\n", __func__);
1507  return false;
1508  }
1509 
1510  // ****** Add outputs for denoms ************ /
1511 
1512  bool fAddFinal = true;
1513  std::vector<CAmount> vecStandardDenoms = CPrivateSend::GetStandardDenominations();
1514 
1515  std::map<CAmount, int> mapDenomCount;
1516  for (auto nDenomValue : vecStandardDenoms) {
1517  mapDenomCount.insert(std::pair<CAmount, int>(nDenomValue, GetWallets()[0]->CountInputsWithAmount(nDenomValue)));
1518  }
1519 
1520  // Will generate outputs for the createdenoms up to privatesendmaxdenoms per denom
1521 
1522  // This works in the way creating PS denoms has traditionally worked, assuming enough funds,
1523  // it will start with the smallest denom then create 11 of those, then go up to the next biggest denom create 11
1524  // and repeat. Previously, once the largest denom was reached, as many would be created were created as possible and
1525  // then any remaining was put into a change address and denominations were created in the same manner a block later.
1526  // Now, in this system, so long as we don't reach PRIVATESEND_DENOM_OUTPUTS_THRESHOLD outputs the process repeats in
1527  // the same transaction, creating up to nPrivateSendDenomsHardCap per denomination in a single transaction.
1528 
1530  for (auto it = vecStandardDenoms.rbegin(); it != vecStandardDenoms.rend(); ++it) {
1531  CAmount nDenomValue = *it;
1532  auto currentDenomIt = mapDenomCount.find(nDenomValue);
1533 
1534  int nOutputs = 0;
1535 
1536  const auto& strFunc = __func__;
1537  auto needMoreOutputs = [&]() {
1538  if (txBuilder.CouldAddOutput(nDenomValue)) {
1539  if (fAddFinal && nBalanceToDenominate > 0 && nBalanceToDenominate < nDenomValue) {
1540  fAddFinal = false; // add final denom only once, only the smalest possible one
1541  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- 1 - FINAL - nDenomValue: %f, nBalanceToDenominate: %f, nOutputs: %d, %s\n",
1542  strFunc, (float) nDenomValue / COIN, (float) nBalanceToDenominate / COIN, nOutputs, txBuilder.ToString());
1543  return true;
1544  } else if (nBalanceToDenominate >= nDenomValue) {
1545  return true;
1546  }
1547  }
1548  return false;
1549  };
1550 
1551  // add each output up to 11 times or until it can't be added again or until we reach nPrivateSendDenomsGoal
1552  while (needMoreOutputs() && nOutputs <= 10 && currentDenomIt->second < privateSendClient.nPrivateSendDenomsGoal) {
1553  // Add output and subtract denomination amount
1554  if (txBuilder.AddOutput(nDenomValue)) {
1555  ++nOutputs;
1556  ++currentDenomIt->second;
1557  nBalanceToDenominate -= nDenomValue;
1558  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- 1 - nDenomValue: %f, nBalanceToDenominate: %f, nOutputs: %d, %s\n",
1559  __func__, (float) nDenomValue / COIN, (float) nBalanceToDenominate / COIN, nOutputs, txBuilder.ToString());
1560  } else {
1561  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- 1 - Error: AddOutput failed for nDenomValue: %f, nBalanceToDenominate: %f, nOutputs: %d, %s\n",
1562  __func__, (float) nDenomValue / COIN, (float) nBalanceToDenominate / COIN, nOutputs, txBuilder.ToString());
1563  return false;
1564  }
1565 
1566  }
1567 
1568  if (txBuilder.GetAmountLeft() == 0 || nBalanceToDenominate <= 0) break;
1569  }
1570 
1571  bool finished = true;
1572  for (const auto it : mapDenomCount) {
1573  // Check if this specific denom could use another loop, check that there aren't nPrivateSendDenomsGoal of this
1574  // denom and that our nValueLeft/nBalanceToDenominate is enough to create one of these denoms, if so, loop again.
1575  if (it.second < privateSendClient.nPrivateSendDenomsGoal && txBuilder.CouldAddOutput(it.first) && nBalanceToDenominate > 0) {
1576  finished = false;
1577  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- 1 - NOT finished - nDenomValue: %f, count: %d, nBalanceToDenominate: %f, %s\n",
1578  __func__, (float) it.first / COIN, it.second, (float) nBalanceToDenominate / COIN, txBuilder.ToString());
1579  break;
1580  }
1581  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- 1 - FINSHED - nDenomValue: %f, count: %d, nBalanceToDenominate: %f, %s\n",
1582  __func__, (float) it.first / COIN, it.second, (float) nBalanceToDenominate / COIN, txBuilder.ToString());
1583  }
1584 
1585  if (finished) break;
1586  }
1587 
1588  // Now that nPrivateSendDenomsGoal worth of each denom have been created or the max number of denoms given the value of the input, do something with the remainder.
1590  CAmount nLargestDenomValue = vecStandardDenoms.front();
1591 
1592  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- 2 - Process remainder: %s\n", __func__, txBuilder.ToString());
1593 
1594  auto countPossibleOutputs = [&](CAmount nAmount) -> int {
1595  std::vector<CAmount> vecOutputs;
1596  while (true) {
1597  // Create an potential output
1598  vecOutputs.push_back(nAmount);
1599  if (!txBuilder.CouldAddOutputs(vecOutputs) || txBuilder.CountOutputs() + vecOutputs.size() > PRIVATESEND_DENOM_OUTPUTS_THRESHOLD) {
1600  // If its not possible to add it due to insufficient amount left or total number of outputs exceeds
1601  // PRIVATESEND_DENOM_OUTPUTS_THRESHOLD drop the output again and stop trying.
1602  vecOutputs.pop_back();
1603  break;
1604  }
1605  }
1606  return static_cast<int>(vecOutputs.size());
1607  };
1608 
1609  // Go big to small
1610  for (auto nDenomValue : vecStandardDenoms) {
1611  int nOutputs = 0;
1612 
1613  // Number of denoms we can create given our denom and the amount of funds we have left
1614  int denomsToCreateValue = countPossibleOutputs(nDenomValue);
1615  // Prefer overshooting the targed balance by larger denoms (hence `+1`) instead of a more
1616  // accurate approximation by many smaller denoms. This is ok because when we get here we
1617  // should have nPrivateSendDenomsGoal of each smaller denom already. Also, without `+1`
1618  // we can end up in a situation when there is already nPrivateSendDenomsHardCap of smaller
1619  // denoms yet we can't mix the remaining nBalanceToDenominate because it's smaller than
1620  // nDenomValue (and thus denomsToCreateBal == 0), so the target would never get reached
1621  // even when there is enough funds for that.
1622  int denomsToCreateBal = (nBalanceToDenominate / nDenomValue) + 1;
1623  // Use the smaller value
1624  int denomsToCreate = denomsToCreateValue > denomsToCreateBal ? denomsToCreateBal : denomsToCreateValue;
1625  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- 2 - nBalanceToDenominate: %f, nDenomValue: %f, denomsToCreateValue: %d, denomsToCreateBal: %d\n",
1626  __func__, (float) nBalanceToDenominate / COIN, (float) nDenomValue / COIN, denomsToCreateValue, denomsToCreateBal);
1627  auto it = mapDenomCount.find(nDenomValue);
1628  for (int i = 0; i < denomsToCreate; i++) {
1629  // Never go above the cap unless it's the largest denom
1630  if (nDenomValue != nLargestDenomValue && it->second >= privateSendClient.nPrivateSendDenomsHardCap) break;
1631 
1632  // Increment helpers, add output and subtract denomination amount
1633  if (txBuilder.AddOutput(nDenomValue)) {
1634  nOutputs++;
1635  it->second++;
1636  nBalanceToDenominate -= nDenomValue;
1637  } else {
1638  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- 2 - Error: AddOutput failed at %d/%d, %s\n", __func__, i + 1, denomsToCreate, txBuilder.ToString());
1639  break;
1640  }
1641  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- 2 - nDenomValue: %f, nBalanceToDenominate: %f, nOutputs: %d, %s\n",
1642  __func__, (float) nDenomValue / COIN, (float) nBalanceToDenominate / COIN, nOutputs, txBuilder.ToString());
1643  if (txBuilder.CountOutputs() >= PRIVATESEND_DENOM_OUTPUTS_THRESHOLD) break;
1644  }
1645  if (txBuilder.CountOutputs() >= PRIVATESEND_DENOM_OUTPUTS_THRESHOLD) break;
1646  }
1647  }
1648 
1649  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- 3 - nBalanceToDenominate: %f, %s\n", __func__, (float) nBalanceToDenominate / COIN, txBuilder.ToString());
1650 
1651  for (const auto it : mapDenomCount) {
1652  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- 3 - DONE - nDenomValue: %f, count: %d\n", __func__, (float) it.first / COIN, it.second);
1653  }
1654 
1655  // No reasons to create mixing collaterals if we can't create denoms to mix
1656  if ((fCreateMixingCollaterals && txBuilder.CountOutputs() == 1) || txBuilder.CountOutputs() == 0) {
1657  return false;
1658  }
1659 
1660  std::string strResult;
1661  if (!txBuilder.Commit(strResult)) {
1662  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- Commit failed: %s\n", __func__, strResult);
1663  return false;
1664  }
1665 
1666  // use the same nCachedLastSuccessBlock as for DS mixing to prevent race
1668 
1669  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::%s -- txid: %s\n", __func__, strResult);
1670 
1671  return true;
1672 }
1673 
1675 {
1676  if (!mixingMasternode) return;
1677 
1678  connman.ForNode(mixingMasternode->pdmnState->addr, [&entry, &connman](CNode* pnode) {
1679  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::RelayIn -- found master, relaying message to %s\n", pnode->addr.ToString());
1680  CNetMsgMaker msgMaker(pnode->GetSendVersion());
1681  connman.PushMessage(pnode, msgMaker.Make(NetMsgType::DSVIN, entry));
1682  return true;
1683  });
1684 }
1685 
1687 {
1688  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientSession::SetState -- nState: %d, nStateNew: %d\n", nState, nStateNew);
1689  nState = nStateNew;
1690 }
1691 
1693 {
1694  nCachedBlockHeight = pindex->nHeight;
1695  LogPrint(BCLog::PRIVATESEND, "CPrivateSendClientManager::UpdatedBlockTip -- nCachedBlockHeight: %d\n", nCachedBlockHeight);
1696 }
1697 
1699 {
1700  if (!fEnablePrivateSend) return;
1701  if (fMasternodeMode) return; // no client-side mixing on masternodes
1702 
1704 
1705  static unsigned int nTick = 0;
1706  static unsigned int nDoAutoNextRun = nTick + PRIVATESEND_AUTO_TIMEOUT_MIN;
1707 
1708  nTick++;
1709  CheckTimeout();
1710  ProcessPendingDsaRequest(connman);
1711  if (nDoAutoNextRun == nTick) {
1712  DoAutomaticDenominating(connman);
1714  }
1715 }
1716 
1718 {
1719  obj.clear();
1720  obj.setObject();
1721  if (mixingMasternode != nullptr) {
1722  assert(mixingMasternode->pdmnState);
1723  obj.push_back(Pair("protxhash", mixingMasternode->proTxHash.ToString()));
1724  obj.push_back(Pair("outpoint", mixingMasternode->collateralOutpoint.ToStringShort()));
1725  obj.push_back(Pair("service", mixingMasternode->pdmnState->addr.ToString()));
1726  }
1728  obj.push_back(Pair("state", GetStateString()));
1729  obj.push_back(Pair("entries_count", GetEntriesCount()));
1730 }
1731 
1733 {
1735  obj.clear();
1736  obj.setObject();
1737  obj.push_back(Pair("enabled", fEnablePrivateSend));
1738  obj.push_back(Pair("running", fPrivateSendRunning));
1739  obj.push_back(Pair("multisession", fPrivateSendMultiSession));
1740  obj.push_back(Pair("max_sessions", nPrivateSendSessions));
1741  obj.push_back(Pair("max_rounds", nPrivateSendRounds));
1742  obj.push_back(Pair("max_amount", nPrivateSendAmount));
1743  obj.push_back(Pair("denoms_goal", nPrivateSendDenomsGoal));
1744  obj.push_back(Pair("denoms_hardcap", nPrivateSendDenomsHardCap));
1745  obj.push_back(Pair("queue_size", GetQueueSize()));
1746 
1747  UniValue arrSessions(UniValue::VARR);
1748  for (const auto& session : deqSessions) {
1749  if (session.GetState() != POOL_STATE_IDLE) {
1750  UniValue objSession(UniValue::VOBJ);
1751  session.GetJsonInfo(objSession);
1752  arrSessions.push_back(objSession);
1753  }
1754  }
1755  obj.push_back(Pair("sessions", arrSessions));
1756 }
bool SubmitDenominate(CConnman &connman)
As a client, submit part of a future mixing transaction to a Masternode to start the process...
CTxMemPool mempool
std::string NetworkIDString() const
Return the BIP70 network string (main, test or regtest)
Definition: chainparams.h:76
Used to keep track of current status of mixing pool.
PoolStatusUpdate nStatusUpdate
Definition: privatesend.h:87
static CAmount GetSmallestDenomination()
Definition: privatesend.h:437
CMasternodeSync masternodeSync
int GetSendVersion() const
Definition: net.cpp:887
void SetState(PoolState nStateNew)
void UpdatedBlockTip(const CBlockIndex *pindex)
std::string ToString(bool fUseGetnameinfo=true) const
Definition: netaddress.cpp:581
bool Commit(std::string &strResult)
Create and Commit the transaction to the wallet.
static bool IsDenominatedAmount(CAmount nInputAmount)
void MilliSleep(int64_t n)
Definition: utiltime.cpp:75
const char * DSACCEPT
Definition: protocol.cpp:47
int GetRandInt(int nMax)
Definition: random.cpp:379
#define TRY_LOCK(cs, name)
Definition: sync.h:180
static CAmount GetCollateralAmount()
Definition: privatesend.h:460
static const std::string REGTEST
std::vector< CPrivateSendEntry > vecEntries
Definition: privatesend.h:364
bool ShutdownRequested()
Definition: init.cpp:179
#define strprintf
Definition: tinyformat.h:1066
bool PrepareDenominate(int nMinRounds, int nMaxRounds, std::string &strErrorRet, const std::vector< std::pair< CTxDSIn, CTxOut > > &vecPSInOutPairsIn, std::vector< std::pair< CTxDSIn, CTxOut > > &vecPSInOutPairsRet, bool fDryRun=false)
step 1: prepare denominated inputs and outputs
bool SignSignature(const CKeyStore &keystore, const CScript &fromPubKey, CMutableTransaction &txTo, unsigned int nIn, const CAmount &amount, int nHashType)
Produce a script signature for a transaction.
Definition: sign.cpp:167
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 SendDenominate(const std::vector< std::pair< CTxDSIn, CTxOut > > &vecPSInOutPairsIn, CConnman &connman)
step 2: send denominated inputs and outputs prepared in step 1
A currently in progress mixing merge and denomination information.
Definition: privatesend.h:215
Implementation of BIP69 https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki.
Definition: transaction.h:352
constexpr deserialize_type deserialize
Definition: serialize.h:43
CCriticalSection cs_main
Definition: validation.cpp:213
std::vector< COutPoint > vecOutPoints
Definition: wallet.h:111
void ProcessPoolStateUpdate(CPrivateSendStatusUpdate psssup)
Process Masternode updates about the progress of mixing.
const char * DSSTATUSUPDATE
Definition: protocol.cpp:52
UniValue ValueFromAmount(const CAmount &amount)
Definition: core_write.cpp:25
static const int PRIVATESEND_KEYS_THRESHOLD_WARNING
void PushMessage(CNode *pnode, CSerializedNetMsg &&msg)
Definition: net.cpp:3733
PoolMessage
Definition: privatesend.h:33
void GetJsonInfo(UniValue &obj) const
static int AmountToDenomination(CAmount nInputAmount)
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:103
std::shared_ptr< const CDeterministicMN > CDeterministicMNCPtr
CMutableTransaction finalMutableTransaction
Definition: privatesend.h:371
static const int PRIVATESEND_QUEUE_TIMEOUT
Definition: privatesend.h:24
bool GetMixingMasternodeInfo(CDeterministicMNCPtr &ret) const
bool IsBlockchainSynced()
static std::vector< CAmount > GetStandardDenominations()
Definition: privatesend.h:436
CDeterministicMNCPtr mixingMasternode
std::unique_ptr< CDeterministicMNManager > deterministicMNManager
static const unsigned char REJECT_OBSOLETE
Definition: validation.h:14
bool CouldAddOutputs(const std::vector< CAmount > &vecOutputAmounts) const
Check if its possible to add multiple outputs as vector of amounts. Returns true if its possible to a...
CMasternodeMetaMan mmetaman
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
CAmount GetAmountLeft() const
Get the amount currently left to add more outputs. Does respect fees.
const char * DSFINALTX
Definition: protocol.cpp:49
Enables simple transaction generation for a given CWallet object.
std::vector< CWallet * > GetWallets()
Definition: wallet.cpp:79
bool CheckDiskSpace(uint64_t nAdditionalBytes)
Check whether enough disk space is available for an incoming block.
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
bool fMasternodeMode
Definition: util.cpp:93
#define LOCK2(cs1, cs2)
Definition: sync.h:179
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
int nWalletBackups
nWalletBackups: 1..10 - number of automatic backups to keep 0 - disabled by command-line -1 - disable...
Definition: util.cpp:102
bool push_back(const UniValue &val)
Definition: univalue.cpp:110
std::string ScriptToAsmStr(const CScript &script, const bool fAttemptSighashDecode=false)
Create the assembly string representation of a CScript object.
Definition: core_write.cpp:86
const char * DSCOMPLETE
Definition: protocol.cpp:51
COutPoint masternodeOutpoint
Definition: privatesend.h:219
static bool IsCollateralValid(const CTransaction &txCollateral)
If the collateral is valid given by a client.
bool StartNewQueue(CAmount nBalanceNeedsAnonymized, CConnman &connman)
CScript AddKey(CWallet *pwalletIn)
bool GetQueueItemAndTry(CPrivateSendQueue &dsqRet)
#define LOCK(cs)
Definition: sync.h:178
const uint256 & GetHash() const
Definition: transaction.h:256
bool DoAutomaticDenominating(CConnman &connman, bool fDryRun=false)
Passively run mixing in the background according to the configuration in settings.
CCriticalSection cs_vecqueue
Definition: privatesend.h:400
Fast randomness source.
Definition: random.h:48
Definition: privatesend.h:173
bool ProcessPendingDsaRequest(CConnman &connman)
int GetQueueSize() const
Definition: privatesend.h:412
std::vector< CPrivateSendQueue > vecPrivateSendQueue
Definition: privatesend.h:403
CPrivateSendAccept GetDSA()
std::vector< COutPoint > vecMasternodesUsed
bool SignFinalTransaction(const CTransaction &finalTransactionNew, CNode *pnode, CConnman &connman)
As a client, check and sign the final transaction.
Definition: net.h:136
CAmount GetAmount() const
Get the amount of this output.
An output of a transaction.
Definition: transaction.h:144
std::string ToString() const
Convert to a string.
NodeId GetId() const
Definition: net.h:973
static std::pair< std::string, UniValue > Pair(const char *cKey, const char *cVal)
Definition: univalue.h:185
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:26
CDeterministicMNCPtr GetRandomNotUsedMasternode()
void CompletedTransaction(PoolMessage nMessageID)
std::vector< CTxOut > vout
Definition: transaction.h:294
bool SelectDenominate(std::string &strErrorRet, std::vector< std::pair< CTxDSIn, CTxOut > > &vecPSInOutPairsRet)
step 0: select denominated inputs and txouts
std::string FormatMoney(const CAmount &n)
Money parsing/formatting utilities.
bool CreateDenominated(CAmount nBalanceToDenominate)
Create denominations.
const char * DSSIGNFINALTX
Definition: protocol.cpp:50
CCriticalSection cs
Definition: txmempool.h:488
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
CKeyHolderStorage keyHolderStorage
const CAddress addr
Definition: net.h:834
bool AddPendingMasternode(const uint256 &proTxHash)
Definition: net.cpp:3305
void ProcessPendingDsaRequest(CConnman &connman)
CCriticalSection cs_privatesend
Definition: privatesend.h:362
bool IsDust(CAmount nAmount) const
Check if an amounts should be considered as dust.
#define LogPrint(category,...)
Definition: util.h:214
Used by CTransactionBuilder to represent its transaction outputs.
static const int PRIVATESEND_DENOM_OUTPUTS_THRESHOLD
void ProcessMessage(CNode *pfrom, const std::string &strCommand, CDataStream &vRecv, CConnman &connman)
std::string GetStateString() const
void AllowMixing(const uint256 &proTxHash)
static bool IsValidDenomination(int nDenom)
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:66
CAmount nAmount
Definition: wallet.h:110
CPendingDsaRequest pendingDsaRequest
CPrivateSendClientManager privateSendClient
std::string ToString() const
Definition: transaction.cpp:71
int GetEntriesCount() const
Definition: privatesend.h:393
const char * DSQUEUE
Definition: protocol.cpp:54
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:170
const CChainParams & Params()
Return the currently selected parameters.
static CAmount GetMaxPoolAmount()
Definition: privatesend.h:456
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:389
bool CouldAddOutput(CAmount nAmountOutput) const
Check it would be possible to add a single output with the amount nAmount. Returns true if its possib...
A virtual base class for key stores.
Definition: keystore.h:19
static const int PRIVATESEND_AUTO_TIMEOUT_MAX
Definition: privatesend.h:23
void DoMaintenance(CConnman &connman)
std::string ToString() const
static const int MIN_PRIVATESEND_PEER_PROTO_VERSION
minimum peer version accepted by mixing pool
Definition: privatesend.h:28
void GetJsonInfo(UniValue &obj) const
int CountOutputs() const
Get the total number of added outputs.
static std::string GetMessageByID(PoolMessage nMessageID)
std::string GetLogString() const
Definition: net.cpp:750
void RelayIn(const CPrivateSendEntry &entry, CConnman &connman)
static CAmount GetMaxCollateralAmount()
Definition: privatesend.h:461
bool setObject()
Definition: univalue.cpp:103
bool IsValidInOuts(const std::vector< CTxIn > &vin, const std::vector< CTxOut > &vout, PoolMessage &nMessageIDRet, bool *fConsumeCollateralRet) const
static const int PRIVATESEND_AUTO_TIMEOUT_MIN
Definition: privatesend.h:22
std::atomic< int > nVersion
Definition: net.h:838
static const int PRIVATESEND_KEYS_THRESHOLD_STOP
std::string GetStatus(bool fWaitForBlock)
static bool IsCollateralAmount(CAmount nInputAmount)
bool IsMasternodeOrDisconnectRequested(const CService &addr)
Definition: net.cpp:3808
bool GetMixingMasternodesInfo(std::vector< CDeterministicMNCPtr > &vecDmnsRet) const
A mutable version of CTransaction.
Definition: transaction.h:291
std::vector< COutPoint > vecOutPointLocked
bool DoAutomaticDenominating(CConnman &connman, bool fDryRun=false)
Passively run mixing in the background according to the configuration in settings.
bool JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman &connman)
void clear()
Definition: univalue.cpp:17
std::deque< CPrivateSendClientSession > deqSessions
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:198
bool MakeCollateralAmounts()
Split up large inputs or make fee sized inputs.
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:183
Information about a peer.
Definition: net.h:800
AssertLockHeld(g_cs_orphans)
void AddUsedMasternode(const COutPoint &outpointMn)
std::string ToString() const
Definition: privatesend.h:277
CMutableTransaction txMyCollateral
static CAmount DenominationToAmount(int nDenom)
void ProcessMessage(CNode *pfrom, const std::string &strCommand, CDataStream &vRecv, CConnman &connman)
bool g_enable_bip61
Enable BIP61 (sending reject messages)
CMasternodeMetaInfoPtr GetMetaInfo(const uint256 &proTxHash, bool fCreate=true)
static std::string DenominationToString(int nDenom)
CTransactionBuilderOutput * AddOutput(CAmount nAmountOutput=0)
Add an output with the amount nAmount. Returns a pointer to the output if it could be added and nullp...
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a boost::optional result...
Definition: util.h:92
static const size_t PRIVATESEND_ENTRY_MAX_SIZE
Definition: privatesend.h:30
bool UpdateAmount(CAmount nAmount)
Try update the amount of this output. Returns true if it was successful and false if not (e...
std::string ToStringShort() const
Definition: transaction.cpp:17
Released under the MIT license