Line data Source code
1 : // Copyright (c) 2014-2025 The Dash Core developers
2 : // Distributed under the MIT/X11 software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #ifndef BITCOIN_COINJOIN_CLIENT_H
6 : #define BITCOIN_COINJOIN_CLIENT_H
7 :
8 : #include <coinjoin/coinjoin.h>
9 : #include <coinjoin/util.h>
10 : #include <evo/types.h>
11 : #include <util/translation.h>
12 :
13 : #include <atomic>
14 : #include <deque>
15 : #include <memory>
16 : #include <ranges>
17 : #include <utility>
18 :
19 : class CCoinJoinClientManager;
20 : class CConnman;
21 : class CDeterministicMNManager;
22 : class ChainstateManager;
23 : class CMasternodeMetaMan;
24 : class CMasternodeSync;
25 : class CNode;
26 : class CTxMemPool;
27 :
28 : class UniValue;
29 :
30 : class CPendingDsaRequest
31 : {
32 : private:
33 : static constexpr int TIMEOUT = 15;
34 :
35 : uint256 proTxHash;
36 : CCoinJoinAccept dsa;
37 4 : int64_t nTimeCreated{0};
38 :
39 : public:
40 12 : CPendingDsaRequest() = default;
41 :
42 2 : CPendingDsaRequest(uint256 proTxHash_, CCoinJoinAccept dsa_) :
43 1 : proTxHash(std::move(proTxHash_)),
44 1 : dsa(std::move(dsa_)),
45 1 : nTimeCreated(GetTime())
46 1 : {
47 2 : }
48 :
49 2 : [[nodiscard]] uint256 GetProTxHash() const { return proTxHash; }
50 2 : [[nodiscard]] CCoinJoinAccept GetDSA() const { return dsa; }
51 4 : [[nodiscard]] bool IsExpired() const { return GetTime() - nTimeCreated > TIMEOUT; }
52 :
53 5 : friend bool operator==(const CPendingDsaRequest& a, const CPendingDsaRequest& b)
54 : {
55 5 : return a.proTxHash == b.proTxHash && a.dsa == b.dsa;
56 : }
57 3 : friend bool operator!=(const CPendingDsaRequest& a, const CPendingDsaRequest& b)
58 : {
59 3 : return !(a == b);
60 : }
61 2 : explicit operator bool() const
62 : {
63 2 : return *this != CPendingDsaRequest();
64 0 : }
65 : };
66 :
67 : class CCoinJoinClientSession : public CCoinJoinBaseSession
68 : {
69 : private:
70 : const std::shared_ptr<wallet::CWallet> m_wallet;
71 : CCoinJoinClientManager& m_clientman;
72 : CDeterministicMNManager& m_dmnman;
73 : CMasternodeMetaMan& m_mn_metaman;
74 : const CMasternodeSync& m_mn_sync;
75 : const llmq::CInstantSendManager& m_isman;
76 : std::vector<COutPoint> vecOutPointLocked;
77 :
78 : bilingual_str strLastMessage;
79 : bilingual_str strAutoDenomResult;
80 :
81 : CDeterministicMNCPtr mixingMasternode;
82 : CMutableTransaction txMyCollateral; // client side collateral
83 : CPendingDsaRequest pendingDsaRequest;
84 :
85 : CKeyHolderStorage keyHolderStorage; // storage for keys used in PrepareDenominate
86 :
87 : /// Create denominations
88 : bool CreateDenominated(CAmount nBalanceToDenominate);
89 : bool CreateDenominated(CAmount nBalanceToDenominate, const wallet::CompactTallyItem& tallyItem, bool fCreateMixingCollaterals)
90 : EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet);
91 :
92 : /// Split up large inputs or make fee sized inputs
93 : bool MakeCollateralAmounts();
94 : bool MakeCollateralAmounts(const wallet::CompactTallyItem& tallyItem, bool fTryDenominated)
95 : EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet);
96 :
97 : bool CreateCollateralTransaction(CMutableTransaction& txCollateral, std::string& strReason)
98 : EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet);
99 :
100 : bool JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman);
101 : bool StartNewQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman);
102 :
103 : /// step 0: select denominated inputs and txouts
104 : bool SelectDenominate(std::string& strErrorRet, std::vector<CTxDSIn>& vecTxDSInRet);
105 : /// step 1: prepare denominated inputs and outputs
106 : bool PrepareDenominate(int nMinRounds, int nMaxRounds, std::string& strErrorRet, const std::vector<CTxDSIn>& vecTxDSIn,
107 : std::vector<std::pair<CTxDSIn, CTxOut>>& vecPSInOutPairsRet, bool fDryRun = false)
108 : EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet);
109 : /// step 2: send denominated inputs and outputs prepared in step 1
110 : bool SendDenominate(const std::vector<std::pair<CTxDSIn, CTxOut> >& vecPSInOutPairsIn, CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_coinjoin);
111 :
112 : /// Process Masternode updates about the progress of mixing
113 : void ProcessPoolStateUpdate(CCoinJoinStatusUpdate psssup);
114 : // Set the 'state' value, with some logging and capturing when the state changed
115 : void SetState(PoolState nStateNew);
116 :
117 : void CompletedTransaction(PoolMessage nMessageID);
118 :
119 : /// As a client, check and sign the final transaction
120 : bool SignFinalTransaction(CNode& peer, CChainState& active_chainstate, CConnman& connman, const CTxMemPool& mempool, const CTransaction& finalTransactionNew) EXCLUSIVE_LOCKS_REQUIRED(!cs_coinjoin);
121 :
122 : void RelayIn(const CCoinJoinEntry& entry, CConnman& connman) const;
123 :
124 : void SetNull() override EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin);
125 :
126 : public:
127 : explicit CCoinJoinClientSession(const std::shared_ptr<wallet::CWallet>& wallet, CCoinJoinClientManager& clientman,
128 : CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman,
129 : const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman);
130 :
131 : void ProcessMessage(CNode& peer, CChainState& active_chainstate, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv);
132 :
133 : void UnlockCoins();
134 :
135 : void ResetPool() EXCLUSIVE_LOCKS_REQUIRED(!cs_coinjoin);
136 :
137 : bilingual_str GetStatus(bool fWaitForBlock) const;
138 :
139 : bool GetMixingMasternodeInfo(CDeterministicMNCPtr& ret) const;
140 :
141 : /// Passively run mixing in the background according to the configuration in settings
142 : bool DoAutomaticDenominating(ChainstateManager& chainman, CConnman& connman, const CTxMemPool& mempool,
143 : bool fDryRun = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_coinjoin);
144 :
145 : /// As a client, submit part of a future mixing transaction to a Masternode to start the process
146 : bool SubmitDenominate(CConnman& connman);
147 :
148 : bool ProcessPendingDsaRequest(CConnman& connman);
149 :
150 : bool CheckTimeout();
151 :
152 : void GetJsonInfo(UniValue& obj) const;
153 : };
154 :
155 : /** Used to keep track of current status of mixing pool
156 : */
157 : class CCoinJoinClientManager
158 : {
159 : private:
160 : const std::shared_ptr<wallet::CWallet> m_wallet;
161 : CDeterministicMNManager& m_dmnman;
162 : CMasternodeMetaMan& m_mn_metaman;
163 : const CMasternodeSync& m_mn_sync;
164 : const llmq::CInstantSendManager& m_isman;
165 : //! Non-owning pointer; null when relay_txes is disabled (no queue processing).
166 : CoinJoinQueueManager* const m_queueman;
167 :
168 : mutable Mutex cs_deqsessions;
169 : // TODO: or map<denom, CCoinJoinClientSession> ??
170 : std::deque<CCoinJoinClientSession> deqSessions GUARDED_BY(cs_deqsessions);
171 :
172 : std::atomic<bool> fMixing{false};
173 :
174 : int nCachedLastSuccessBlock{0};
175 : int nMinBlocksToWait{1}; // how many blocks to wait for after one successful mixing tx in non-multisession mode
176 : bilingual_str strAutoDenomResult;
177 :
178 : // Keep track of current block height
179 : int nCachedBlockHeight{0};
180 :
181 : bool WaitForAnotherBlock() const;
182 :
183 : // Make sure we have enough keys since last backup
184 : bool CheckAutomaticBackup();
185 :
186 : public:
187 : int nCachedNumBlocks{std::numeric_limits<int>::max()}; // used for the overview screen
188 : bool fCreateAutoBackups{true}; // builtin support for automatic backups
189 :
190 : CCoinJoinClientManager() = delete;
191 : CCoinJoinClientManager(const CCoinJoinClientManager&) = delete;
192 : CCoinJoinClientManager& operator=(const CCoinJoinClientManager&) = delete;
193 : explicit CCoinJoinClientManager(const std::shared_ptr<wallet::CWallet>& wallet, CDeterministicMNManager& dmnman,
194 : CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync,
195 : const llmq::CInstantSendManager& isman, CoinJoinQueueManager* queueman);
196 : ~CCoinJoinClientManager();
197 :
198 : void ProcessMessage(CNode& peer, CChainState& active_chainstate, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
199 :
200 : bool StartMixing();
201 : void StopMixing();
202 : bool IsMixing() const;
203 : void ResetPool() EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
204 :
205 : std::vector<std::string> GetStatuses() const EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
206 : std::string GetSessionDenoms() EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
207 :
208 : bool GetMixingMasternodesInfo(std::vector<CDeterministicMNCPtr>& vecDmnsRet) const EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
209 :
210 : /// Passively run mixing in the background according to the configuration in settings
211 : bool DoAutomaticDenominating(ChainstateManager& chainman, CConnman& connman, const CTxMemPool& mempool,
212 : bool fDryRun = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
213 :
214 : bool TrySubmitDenominate(const uint256& proTxHash, CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
215 : bool MarkAlreadyJoinedQueueAsTried(CCoinJoinQueue& dsq) const EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
216 : bool GetQueueItemAndTry(CCoinJoinQueue& dsq) const;
217 :
218 : void CheckTimeout() EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
219 :
220 : void ProcessPendingDsaRequest(CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
221 :
222 : void AddUsedMasternode(const uint256& proTxHash);
223 : CDeterministicMNCPtr GetRandomNotUsedMasternode();
224 :
225 : void UpdatedSuccessBlock();
226 :
227 : void UpdatedBlockTip(const CBlockIndex* pindex);
228 :
229 : void DoMaintenance(ChainstateManager& chainman, CConnman& connman, const CTxMemPool& mempool)
230 : EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
231 :
232 : void GetJsonInfo(UniValue& obj) const EXCLUSIVE_LOCKS_REQUIRED(!cs_deqsessions);
233 : };
234 :
235 : #endif // BITCOIN_COINJOIN_CLIENT_H
|