Skip to content

Commit 41a6613

Browse files
refactor: subsume CoinJoin objects under CJContext, deglobalize coinJoin{ClientQueueManager,Server} (#5337)
## Motivation CoinJoin's subsystems are initialized by variables and managers that occupy the global context. The _extent_ to which these subsystems entrench themselves into the codebase is difficult to assess and moving them out of the global context forces us to enumerate the subsystems in the codebase that rely on CoinJoin logic and enumerate the order in which components are initialized and destroyed. Keeping this in mind, the scope of this pull request aims to: * Reduce the amount of CoinJoin-specific entities present in the global scope * Make the remaining usage of these entities in the global scope explicit and easily searchable ## Additional Information * The initialization of `CCoinJoinClientQueueManager` is dependent on blocks-only mode being disabled (which can be alternatively interpreted as enabling the relay of transactions). The same applies to `CBlockPolicyEstimator`, which `CCoinJoinClientQueueManager` depends. Therefore, `CCoinJoinClientQueueManager` is only initialized if transaction relaying is enabled and so is its scheduled maintenance task. This can be found by looking at `init.cpp` [here](https://github.com/dashpay/dash/blob/93f8df1c31fdce6a14f149acfdff22678c3f22ca/src/init.cpp#L1681-L1683), [here](https://github.com/dashpay/dash/blob/93f8df1c31fdce6a14f149acfdff22678c3f22ca/src/init.cpp#L2253-L2255) and [here](https://github.com/dashpay/dash/blob/93f8df1c31fdce6a14f149acfdff22678c3f22ca/src/init.cpp#L2326-L2327). For this reason, `CBlockPolicyEstimator` is not a member of `CJContext` and its usage is fulfilled by passing it as a reference when initializing the scheduling task. * `CJClientManager` has not used `CConnman` or `CTxMemPool` as `const` as existing code that is outside the scope of this PR would cast away constness, which would be unacceptable. Furthermore, some logical paths are taken that will grind to a halt if they are stored as `const`. Examples of such a call chains would be: * `CJClientManager::DoMaintenance > CCoinJoinClientManager::DoMaintenance > DoAutomaticDenominating > CCoinJoinClientSession::DoAutomaticDenominating > CCoinJoinClientSession::StartNewQueue > CConnman::AddPendingMasternode` which modifies `CConnman::vPendingMasternodes`, which is non-const behaviour * `CJClientManager::DoMaintenance > CCoinJoinClientManager::DoMaintenance > DoAutomaticDenominating > CCoinJoin::IsCollateralValid > AcceptToMemoryPool` which adds a transaction to the memory pool, which is non-const behaviour * There were cppcheck [linter failures](#5337 (comment)) that seemed to be caused by the usage of `Assert` in `coinjoin/client.h`. This seems to be resolved by backporting [bitcoin#24714](bitcoin#24714). (Thanks @knst!) * Depends on #5546 --------- Co-authored-by: Kittywhiskers Van Gogh <63189531+kittywhiskers@users.noreply.github.com> Co-authored-by: PastaPastaPasta <6443210+PastaPastaPasta@users.noreply.github.com>
1 parent 38e7043 commit 41a6613

31 files changed

+477
-332
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ BITCOIN_CORE_H = \
149149
clientversion.h \
150150
coinjoin/coinjoin.h \
151151
coinjoin/client.h \
152+
coinjoin/context.h \
152153
coinjoin/options.h \
153154
coinjoin/server.h \
154155
coinjoin/util.h \
@@ -391,6 +392,7 @@ libbitcoin_server_a_SOURCES = \
391392
blockfilter.cpp \
392393
chain.cpp \
393394
coinjoin/coinjoin.cpp \
395+
coinjoin/context.cpp \
394396
coinjoin/options.cpp \
395397
coinjoin/server.cpp \
396398
consensus/tx_verify.cpp \

src/coinjoin/client.cpp

Lines changed: 171 additions & 172 deletions
Large diffs are not rendered by default.

src/coinjoin/client.h

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,31 @@
77

88
#include <coinjoin/util.h>
99
#include <coinjoin/coinjoin.h>
10+
#include <util/check.h>
1011
#include <util/translation.h>
1112

1213
#include <atomic>
1314
#include <deque>
15+
#include <memory>
1416
#include <utility>
1517

16-
class CDeterministicMN;
17-
using CDeterministicMNCPtr = std::shared_ptr<const CDeterministicMN>;
18-
18+
class CBlockPolicyEstimator;
1919
class CCoinJoinClientManager;
2020
class CCoinJoinClientQueueManager;
21-
22-
class CBlockPolicyEstimator;
2321
class CConnman;
22+
class CDeterministicMN;
23+
class CJClientManager;
2424
class CNode;
25+
class CMasternodeSync;
2526
class CTxMemPool;
2627
class PeerManager;
2728

2829
class UniValue;
29-
class CMasternodeSync;
3030

31+
using CDeterministicMNCPtr = std::shared_ptr<const CDeterministicMN>;
3132

3233
// The main object for accessing mixing
33-
extern std::map<const std::string, std::shared_ptr<CCoinJoinClientManager>> coinJoinClientManagers;
34-
35-
// The object to track mixing queues
36-
extern std::unique_ptr<CCoinJoinClientQueueManager> coinJoinClientQueueManager;
34+
extern std::unique_ptr<CJClientManager> coinJoinClientManagers;
3735

3836
class CPendingDsaRequest
3937
{
@@ -72,10 +70,53 @@ class CPendingDsaRequest
7270
}
7371
};
7472

73+
class CJClientManager {
74+
public:
75+
using wallet_name_cjman_map = std::map<const std::string, std::unique_ptr<CCoinJoinClientManager>>;
76+
77+
public:
78+
CJClientManager(CConnman& connman, CTxMemPool& mempool, const CMasternodeSync& mn_sync,
79+
const std::unique_ptr<CCoinJoinClientQueueManager>& queueman)
80+
: m_connman(connman), m_mempool(mempool), m_mn_sync(mn_sync), m_queueman(queueman) {}
81+
~CJClientManager() {
82+
for (auto& [wallet_name, cj_man] : m_wallet_manager_map) {
83+
cj_man.reset();
84+
}
85+
}
86+
87+
void Add(CWallet& wallet);
88+
void DoMaintenance(CBlockPolicyEstimator& fee_estimator);
89+
90+
void Remove(const std::string& name) {
91+
m_wallet_manager_map.erase(name);
92+
}
93+
94+
CCoinJoinClientManager* Get(const CWallet& wallet) const {
95+
auto it = m_wallet_manager_map.find(wallet.GetName());
96+
return (it != m_wallet_manager_map.end()) ? it->second.get() : nullptr;
97+
}
98+
99+
const wallet_name_cjman_map& raw() const { return m_wallet_manager_map; }
100+
101+
private:
102+
CConnman& m_connman;
103+
CTxMemPool& m_mempool;
104+
105+
const CMasternodeSync& m_mn_sync;
106+
const std::unique_ptr<CCoinJoinClientQueueManager>& m_queueman;
107+
108+
wallet_name_cjman_map m_wallet_manager_map;
109+
};
110+
75111
class CCoinJoinClientSession : public CCoinJoinBaseSession
76112
{
77113
private:
114+
CWallet& m_wallet;
115+
CJClientManager& m_clientman;
116+
CCoinJoinClientManager& m_manager;
117+
78118
const CMasternodeSync& m_mn_sync;
119+
const std::unique_ptr<CCoinJoinClientQueueManager>& m_queueman;
79120

80121
std::vector<COutPoint> vecOutPointLocked;
81122

@@ -88,8 +129,6 @@ class CCoinJoinClientSession : public CCoinJoinBaseSession
88129

89130
CKeyHolderStorage keyHolderStorage; // storage for keys used in PrepareDenominate
90131

91-
CWallet& mixingWallet;
92-
93132
/// Create denominations
94133
bool CreateDenominated(CBlockPolicyEstimator& fee_estimator, CAmount nBalanceToDenominate);
95134
bool CreateDenominated(CBlockPolicyEstimator& fee_estimator, CAmount nBalanceToDenominate, const CompactTallyItem& tallyItem, bool fCreateMixingCollaterals);
@@ -125,10 +164,9 @@ class CCoinJoinClientSession : public CCoinJoinBaseSession
125164
void SetNull() EXCLUSIVE_LOCKS_REQUIRED(cs_coinjoin);
126165

127166
public:
128-
explicit CCoinJoinClientSession(CWallet& pwallet, const CMasternodeSync& mn_sync) :
129-
m_mn_sync(mn_sync), mixingWallet(pwallet)
130-
{
131-
}
167+
explicit CCoinJoinClientSession(CWallet& pwallet, CJClientManager& clientman, const CMasternodeSync& mn_sync,
168+
const std::unique_ptr<CCoinJoinClientQueueManager>& queueman) :
169+
m_wallet(pwallet), m_clientman(clientman), m_manager(*Assert(clientman.Get(pwallet))), m_mn_sync(mn_sync), m_queueman(queueman) {}
132170

133171
void ProcessMessage(CNode& peer, PeerManager& peerman, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv);
134172

@@ -159,12 +197,13 @@ class CCoinJoinClientQueueManager : public CCoinJoinBaseManager
159197
{
160198
private:
161199
CConnman& connman;
200+
CJClientManager& m_clientman;
162201
const CMasternodeSync& m_mn_sync;
163202
mutable Mutex cs_ProcessDSQueue;
164203

165204
public:
166-
explicit CCoinJoinClientQueueManager(CConnman& _connman, const CMasternodeSync& mn_sync) :
167-
connman(_connman), m_mn_sync(mn_sync) {};
205+
explicit CCoinJoinClientQueueManager(CConnman& _connman, CJClientManager& clientman, const CMasternodeSync& mn_sync) :
206+
connman(_connman), m_clientman(clientman), m_mn_sync(mn_sync) {};
168207

169208
void ProcessMessage(const CNode& peer, PeerManager& peerman, std::string_view msg_type, CDataStream& vRecv) LOCKS_EXCLUDED(cs_vecqueue);
170209
void ProcessDSQueue(const CNode& peer, PeerManager& peerman, CDataStream& vRecv);
@@ -176,10 +215,14 @@ class CCoinJoinClientQueueManager : public CCoinJoinBaseManager
176215
class CCoinJoinClientManager
177216
{
178217
private:
179-
// Keep track of the used Masternodes
180-
std::vector<COutPoint> vecMasternodesUsed;
218+
CWallet& m_wallet;
219+
CJClientManager& m_clientman;
181220

182221
const CMasternodeSync& m_mn_sync;
222+
const std::unique_ptr<CCoinJoinClientQueueManager>& m_queueman;
223+
224+
// Keep track of the used Masternodes
225+
std::vector<COutPoint> vecMasternodesUsed;
183226

184227
mutable Mutex cs_deqsessions;
185228
// TODO: or map<denom, CCoinJoinClientSession> ??
@@ -191,8 +234,6 @@ class CCoinJoinClientManager
191234
int nMinBlocksToWait{1}; // how many blocks to wait for after one successful mixing tx in non-multisession mode
192235
bilingual_str strAutoDenomResult;
193236

194-
CWallet& mixingWallet;
195-
196237
// Keep track of current block height
197238
int nCachedBlockHeight{0};
198239

@@ -209,8 +250,9 @@ class CCoinJoinClientManager
209250
CCoinJoinClientManager(CCoinJoinClientManager const&) = delete;
210251
CCoinJoinClientManager& operator=(CCoinJoinClientManager const&) = delete;
211252

212-
explicit CCoinJoinClientManager(CWallet& wallet, const CMasternodeSync& mn_sync) :
213-
m_mn_sync(mn_sync), mixingWallet(wallet) {}
253+
explicit CCoinJoinClientManager(CWallet& wallet, CJClientManager& clientman, const CMasternodeSync& mn_sync,
254+
const std::unique_ptr<CCoinJoinClientQueueManager>& queueman) :
255+
m_wallet(wallet), m_clientman(clientman), m_mn_sync(mn_sync), m_queueman(queueman) {}
214256

215257
void ProcessMessage(CNode& peer, PeerManager& peerman, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv) LOCKS_EXCLUDED(cs_deqsessions);
216258

@@ -246,7 +288,4 @@ class CCoinJoinClientManager
246288
void GetJsonInfo(UniValue& obj) const LOCKS_EXCLUDED(cs_deqsessions);
247289
};
248290

249-
250-
void DoCoinJoinMaintenance(CConnman& connman, CBlockPolicyEstimator& fee_estimator, CTxMemPool& mempool);
251-
252291
#endif // BITCOIN_COINJOIN_CLIENT_H

src/coinjoin/context.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) 2023 The Dash Core developers
2+
// Distributed under the MIT/X11 software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <coinjoin/context.h>
6+
7+
#include <net.h>
8+
#include <policy/fees.h>
9+
#include <txmempool.h>
10+
11+
#ifdef ENABLE_WALLET
12+
#include <coinjoin/client.h>
13+
#endif // ENABLE_WALLET
14+
#include <coinjoin/server.h>
15+
16+
CJContext::CJContext(CChainState& chainstate, CConnman& connman, CTxMemPool& mempool, const CMasternodeSync& mn_sync, bool relay_txes) :
17+
#ifdef ENABLE_WALLET
18+
clientman {
19+
[&]() -> CJClientManager* const {
20+
assert(::coinJoinClientManagers == nullptr);
21+
::coinJoinClientManagers = std::make_unique<CJClientManager>(connman, mempool, mn_sync, queueman);
22+
return ::coinJoinClientManagers.get();
23+
}()
24+
},
25+
queueman {relay_txes ? std::make_unique<CCoinJoinClientQueueManager>(connman, *clientman, mn_sync) : nullptr},
26+
#endif // ENABLE_WALLET
27+
server{std::make_unique<CCoinJoinServer>(chainstate, connman, mempool, mn_sync)}
28+
{}
29+
30+
CJContext::~CJContext() {
31+
#ifdef ENABLE_WALLET
32+
::coinJoinClientManagers.reset();
33+
#endif // ENABLE_WALLET
34+
}

src/coinjoin/context.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) 2023 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_CONTEXT_H
6+
#define BITCOIN_COINJOIN_CONTEXT_H
7+
8+
#if defined(HAVE_CONFIG_H)
9+
#include <config/bitcoin-config.h>
10+
#endif
11+
12+
#include <memory>
13+
14+
class CBlockPolicyEstimator;
15+
class CChainState;
16+
class CCoinJoinServer;
17+
class CConnman;
18+
class CMasternodeSync;
19+
class CTxMemPool;
20+
21+
#ifdef ENABLE_WALLET
22+
class CCoinJoinClientQueueManager;
23+
class CJClientManager;
24+
#endif // ENABLE_WALLET
25+
26+
struct CJContext {
27+
CJContext() = delete;
28+
CJContext(const CJContext&) = delete;
29+
CJContext(CChainState& chainstate, CConnman& connman, CTxMemPool& mempool, const CMasternodeSync& mn_sync, bool relay_txes);
30+
~CJContext();
31+
32+
#ifdef ENABLE_WALLET
33+
CJClientManager* const clientman;
34+
const std::unique_ptr<CCoinJoinClientQueueManager> queueman;
35+
#endif // ENABLE_WALLET
36+
const std::unique_ptr<CCoinJoinServer> server;
37+
};
38+
39+
#endif // BITCOIN_COINJOIN_CONTEXT_H

src/coinjoin/server.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
#include <univalue.h>
2525

26-
std::unique_ptr<CCoinJoinServer> coinJoinServer;
2726
constexpr static CAmount DEFAULT_MAX_RAW_TX_FEE{COIN / 10};
2827

2928
void CCoinJoinServer::ProcessMessage(CNode& peer, PeerManager& peerman, std::string_view msg_type, CDataStream& vRecv)
@@ -886,17 +885,15 @@ void CCoinJoinServer::SetState(PoolState nStateNew)
886885
nState = nStateNew;
887886
}
888887

889-
void CCoinJoinServer::DoMaintenance() const
888+
void CCoinJoinServer::DoMaintenance()
890889
{
891890
if (!fMasternodeMode) return; // only run on masternodes
892891
if (!m_mn_sync.IsBlockchainSynced()) return;
893892
if (ShutdownRequested()) return;
894893

895-
if (!coinJoinServer) return;
896-
897-
coinJoinServer->CheckForCompleteQueue();
898-
coinJoinServer->CheckPool();
899-
coinJoinServer->CheckTimeout();
894+
CheckForCompleteQueue();
895+
CheckPool();
896+
CheckTimeout();
900897
}
901898

902899
void CCoinJoinServer::GetJsonInfo(UniValue& obj) const

src/coinjoin/server.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ class PeerManager;
1515

1616
class UniValue;
1717

18-
// The main object for accessing mixing
19-
extern std::unique_ptr<CCoinJoinServer> coinJoinServer;
20-
2118
/** Used to keep track of current status of mixing pool
2219
*/
2320
class CCoinJoinServer : public CCoinJoinBaseSession, public CCoinJoinBaseManager
@@ -96,7 +93,7 @@ class CCoinJoinServer : public CCoinJoinBaseSession, public CCoinJoinBaseManager
9693
void CheckTimeout();
9794
void CheckForCompleteQueue();
9895

99-
void DoMaintenance() const;
96+
void DoMaintenance();
10097

10198
void GetJsonInfo(UniValue& obj) const;
10299
};

src/dsnotificationinterface.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#ifdef ENABLE_WALLET
88
#include <coinjoin/client.h>
99
#endif // ENABLE_WALLET
10+
#include <coinjoin/context.h>
1011
#include <dsnotificationinterface.h>
1112
#include <governance/governance.h>
1213
#include <masternode/sync.h>
@@ -23,8 +24,9 @@
2324

2425
CDSNotificationInterface::CDSNotificationInterface(CConnman& _connman,
2526
CMasternodeSync& _mn_sync, const std::unique_ptr<CDeterministicMNManager>& _dmnman,
26-
CGovernanceManager& _govman, const std::unique_ptr<LLMQContext>& _llmq_ctx
27-
) : connman(_connman), m_mn_sync(_mn_sync), dmnman(_dmnman), govman(_govman), llmq_ctx(_llmq_ctx) {}
27+
CGovernanceManager& _govman, const std::unique_ptr<LLMQContext>& _llmq_ctx,
28+
const std::unique_ptr<CJContext>& _cj_ctx
29+
) : connman(_connman), m_mn_sync(_mn_sync), dmnman(_dmnman), govman(_govman), llmq_ctx(_llmq_ctx), cj_ctx(_cj_ctx) {}
2830

2931
void CDSNotificationInterface::InitializeCurrentBlockTip()
3032
{
@@ -66,7 +68,7 @@ void CDSNotificationInterface::UpdatedBlockTip(const CBlockIndex *pindexNew, con
6668

6769
CCoinJoin::UpdatedBlockTip(pindexNew, *llmq_ctx->clhandler, m_mn_sync);
6870
#ifdef ENABLE_WALLET
69-
for (auto& pair : coinJoinClientManagers) {
71+
for (auto& pair : cj_ctx->clientman->raw()) {
7072
pair.second->UpdatedBlockTip(pindexNew);
7173
}
7274
#endif // ENABLE_WALLET

src/dsnotificationinterface.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@ class CConnman;
1111
class CDeterministicMNManager;
1212
class CGovernanceManager;
1313
class CMasternodeSync;
14+
struct CJContext;
1415
struct LLMQContext;
1516

1617
class CDSNotificationInterface : public CValidationInterface
1718
{
1819
public:
1920
explicit CDSNotificationInterface(CConnman& _connman,
2021
CMasternodeSync& _mn_sync, const std::unique_ptr<CDeterministicMNManager>& _dmnman,
21-
CGovernanceManager& _govman, const std::unique_ptr<LLMQContext>& _llmq_ctx);
22+
CGovernanceManager& _govman, const std::unique_ptr<LLMQContext>& _llmq_ctx,
23+
const std::unique_ptr<CJContext>& _cj_ctx);
2224
virtual ~CDSNotificationInterface() = default;
2325

2426
// a small helper to initialize current block height in sub-modules on startup
@@ -45,6 +47,7 @@ class CDSNotificationInterface : public CValidationInterface
4547
CGovernanceManager& govman;
4648

4749
const std::unique_ptr<LLMQContext>& llmq_ctx;
50+
const std::unique_ptr<CJContext>& cj_ctx;
4851
};
4952

5053
#endif // BITCOIN_DSNOTIFICATIONINTERFACE_H

src/dummywallet.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class DummyWalletInit : public WalletInitInterface {
2424

2525
// Dash Specific WalletInitInterface InitCoinJoinSettings
2626
void AutoLockMasternodeCollaterals() const override {}
27-
void InitCoinJoinSettings() const override {}
27+
void InitCoinJoinSettings(const CJClientManager& clientman) const override {}
2828
bool InitAutoBackup() const override {return true;}
2929
};
3030

@@ -74,7 +74,7 @@ const WalletInitInterface& g_wallet_init_interface = DummyWalletInit();
7474

7575
namespace interfaces {
7676

77-
std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet)
77+
std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet, const CJClientManager& clientman)
7878
{
7979
throw std::logic_error("Wallet function called in non-wallet build.");
8080
}

0 commit comments

Comments
 (0)