Skip to content

Commit 22526ae

Browse files
Merge #7248: refactor: simplify CoinJoin class hierarchy
eb2142d fix: added missing thread annotation for CJWalletManagerImpl (Konstantin Akimov) 40cd08d refactor: rename CCoinJoinBaseManager to CoinJoinQueueManager and make it non-virtual (Konstantin Akimov) 6fae09a refactor: remove inheritance from CCoinJoinBaseManager in src/test/coinjoin_basemanager_tests.cpp (Konstantin Akimov) a0f39f2 refactor: removed CCoinJoinBaseManager from inheritance of CCoinJoinServer and make it a member (Konstantin Akimov) 72229ce refactor: inline class CCoinJoinClientQueueManager to CJWalletManagerImpl (Konstantin Akimov) 3b1c2da refactor: inline the middleman class CoinJoinWalletManager to CJWalletManagerImpl (Konstantin Akimov) e2d8247 refactor: pass directly reference to CCoinJoinClientManager& instead unique_ptr inside ForEachCJClientMan (Konstantin Akimov) 689b4ec refactor: remove passing pointer to unique_ptr to more clear sequence of object initializtion in CJ (Konstantin Akimov) Pull request description: ## Issue being fixed or feature implemented Current coinjoin subsystem have multiple classes that inherits from each other but some of them doesn't provide any real abstraction level yet complicate architecture. CJWalletManagerImpl, CCoinJoinClientManager, and CCoinJoinClientQueueManager are 2 separate pieces of implementation of CJWalletManager while CJWalletManagerImpl is already private and could keep all implementation inside. ## What was done? This PR simplify CJ architecture by removing boiler code and unneeded abstraction levels to make code easier to support, read and improve. The changes for this PR has been spotted and half-done during #7234 but it's not a direct dependency of final solution, so far as it was possible to fully cut CJ from dash-chainstate implementation. - replaces all references to unique_ptr to just a reference or just unique_ptr to more clear sequence of object initialization in CJ and ownership - inline the middleman class CoinJoinWalletManager to CJWalletManagerImpl which is already private and hidden - remove class CCoinJoinClientQueueManager; logic inlined into CJWalletManagerImpl - remove interface CoinJoinQueueNotify - que notification no longer needed as a separate abstraction - replaced inheritance of CCoinJoinServer : public CCoinJoinBaseManager to composition (m_queueman member) - remove inheritance of regression tests from CCoinJoinBaseManager - rename CCoinJoinBaseManager to CoinJoinQueueManager and make it non-virtual ## CoinJoin Class Diagram — Before vs After [by claude] BEFORE CCoinJoinBaseManager CoinJoinQueueNotify (virtual ctor/dtor) (interface) - vecCoinJoinQueue - OnQueueUpdate() [pure] - cs_vecqueue ▲ ▲ │ inherits │ implements ├─────────────────┐ │ CCoinJoinClientQueueManager CCoinJoinClientManager (owned by CJWalletManagerImpl) (map entry per wallet) │ │ inherits │ CCoinJoinServer ──also inherits──▶ CCoinJoinBaseSession ▲ │ inherits CCoinJoinClientSession CJWalletManager (abstract) └── CJWalletManagerImpl ├── unique_ptr<CCoinJoinClientQueueManager> m_basequeueman └── map<wallet* → CCoinJoinClientManager> --- AFTER CoinJoinQueueManager ← renamed (no C prefix), no virtual ctor/dtor - vecCoinJoinQueue no longer a base class at all - cs_vecqueue + TryHasQueueFromMasternode() new TRY_LOCK helpers + TryCheckDuplicate() + TryAddQueue() CCoinJoinServer ──inherits──▶ CCoinJoinBaseSession - m_queueman: CoinJoinQueueManager ← OWNED by value (composition) ▲ │ inherits CCoinJoinClientSession CJWalletManager (abstract) └── CJWalletManagerImpl ├── unique_ptr<CoinJoinQueueManager> m_queueman ← nullptr if !relay_txes └── map<wallet* → CCoinJoinClientManager> │ │ CCoinJoinClientManager │ - m_queueman: CoinJoinQueueManager* ← non-owning ptr │ (points into CJWalletManagerImpl::m_queueman) ## How Has This Been Tested? Run unit & functional tests. ## Breaking Changes N/A ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone ACKs for top commit: UdjinM6: utACK eb2142d Tree-SHA512: 03a648885d86c6e251296b3315ddf2ffb0ab3839526cf10a52bb36f53dc7ff1888bc45f69bbdcddd8a32bd940955cf6e8487e84062d0dde9daa32317721eeb5a
2 parents 8fefedb + eb2142d commit 22526ae

11 files changed

Lines changed: 342 additions & 438 deletions

File tree

contrib/auto_gdb/simple_class_obj.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"CMasternodeBroadcast", "CMasternodePing",
1515
"CMasternodeMan", "CDarksendQueue", "CDarkSendEntry",
1616
"CTransaction", "CMutableTransaction", "CCoinJoinBaseSession",
17-
"CCoinJoinBaseManager", "CCoinJoinClientSession",
17+
"CoinJoinQueueManager", "CCoinJoinClientSession",
1818
"CCoinJoinClientManager", "CCoinJoinServer", "CMasternodePayments",
1919
"CMasternodePaymentVote", "CMasternodeBlockPayees",
2020
"CMasternodePayee", "CInstantSend", "CTxLockRequest",

src/Makefile.test.include

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ BITCOIN_TESTS =\
122122
test/governance_validators_tests.cpp \
123123
test/coinjoin_inouts_tests.cpp \
124124
test/coinjoin_dstxmanager_tests.cpp \
125-
test/coinjoin_basemanager_tests.cpp \
126125
test/coinjoin_queue_tests.cpp \
127126
test/hash_tests.cpp \
128127
test/httpserver_tests.cpp \

src/coinjoin/client.cpp

Lines changed: 10 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -40,122 +40,10 @@ using wallet::CoinType;
4040
using wallet::CWallet;
4141
using wallet::ReserveDestination;
4242

43-
CCoinJoinClientQueueManager::CCoinJoinClientQueueManager(CoinJoinWalletManager& walletman, CDeterministicMNManager& dmnman,
44-
CMasternodeMetaMan& mn_metaman, const CMasternodeSync& mn_sync) :
45-
m_walletman{walletman},
46-
m_dmnman{dmnman},
47-
m_mn_metaman{mn_metaman},
48-
m_mn_sync{mn_sync}
49-
{
50-
}
51-
52-
CCoinJoinClientQueueManager::~CCoinJoinClientQueueManager() = default;
53-
54-
MessageProcessingResult CCoinJoinClientQueueManager::ProcessMessage(NodeId from, CConnman& connman,
55-
std::string_view msg_type, CDataStream& vRecv)
56-
{
57-
if (msg_type != NetMsgType::DSQUEUE) {
58-
return {};
59-
}
60-
if (!m_mn_sync.IsBlockchainSynced()) return {};
61-
62-
assert(m_mn_metaman.IsValid());
63-
64-
CCoinJoinQueue dsq;
65-
vRecv >> dsq;
66-
67-
MessageProcessingResult ret{};
68-
ret.m_to_erase = CInv{MSG_DSQ, dsq.GetHash()};
69-
70-
if (dsq.masternodeOutpoint.IsNull() && dsq.m_protxHash.IsNull()) {
71-
ret.m_error = MisbehavingError{100};
72-
return ret;
73-
}
74-
75-
const auto tip_mn_list = m_dmnman.GetListAtChainTip();
76-
if (dsq.masternodeOutpoint.IsNull()) {
77-
if (auto dmn = tip_mn_list.GetValidMN(dsq.m_protxHash)) {
78-
dsq.masternodeOutpoint = dmn->collateralOutpoint;
79-
} else {
80-
ret.m_error = MisbehavingError{10};
81-
return ret;
82-
}
83-
}
84-
85-
{
86-
LOCK(cs_ProcessDSQueue);
87-
88-
{
89-
LOCK(cs_vecqueue);
90-
// process every dsq only once
91-
for (const auto &q: vecCoinJoinQueue) {
92-
if (q == dsq) {
93-
return ret;
94-
}
95-
if (q.fReady == dsq.fReady && q.masternodeOutpoint == dsq.masternodeOutpoint) {
96-
// no way the same mn can send another dsq with the same readiness this soon
97-
LogPrint(BCLog::COINJOIN, /* Continued */
98-
"DSQUEUE -- Peer %d is sending WAY too many dsq messages for a masternode with collateral %s\n",
99-
from, dsq.masternodeOutpoint.ToStringShort());
100-
return ret;
101-
}
102-
}
103-
} // cs_vecqueue
104-
105-
LogPrint(BCLog::COINJOIN, "DSQUEUE -- %s new\n", dsq.ToString());
106-
107-
if (dsq.IsTimeOutOfBounds()) return ret;
108-
109-
auto dmn = tip_mn_list.GetValidMNByCollateral(dsq.masternodeOutpoint);
110-
if (!dmn) return ret;
111-
112-
if (dsq.m_protxHash.IsNull()) {
113-
dsq.m_protxHash = dmn->proTxHash;
114-
}
115-
116-
if (!dsq.CheckSignature(dmn->pdmnState->pubKeyOperator.Get())) {
117-
ret.m_error = MisbehavingError{10};
118-
return ret;
119-
}
120-
121-
// if the queue is ready, submit if we can
122-
if (dsq.fReady &&
123-
m_walletman.ForAnyCJClientMan([&connman, &dmn](std::unique_ptr<CCoinJoinClientManager>& clientman) {
124-
return clientman->TrySubmitDenominate(dmn->proTxHash, connman);
125-
})) {
126-
LogPrint(BCLog::COINJOIN, "DSQUEUE -- CoinJoin queue is ready, masternode=%s, queue=%s\n", dmn->proTxHash.ToString(), dsq.ToString());
127-
return ret;
128-
} else {
129-
if (m_mn_metaman.IsMixingThresholdExceeded(dmn->proTxHash, tip_mn_list.GetCounts().enabled())) {
130-
LogPrint(BCLog::COINJOIN, "DSQUEUE -- Masternode %s is sending too many dsq messages\n",
131-
dmn->proTxHash.ToString());
132-
return ret;
133-
}
134-
m_mn_metaman.AllowMixing(dmn->proTxHash);
135-
136-
LogPrint(BCLog::COINJOIN, "DSQUEUE -- new CoinJoin queue, masternode=%s, queue=%s\n", dmn->proTxHash.ToString(), dsq.ToString());
137-
138-
m_walletman.ForAnyCJClientMan([&dsq](const std::unique_ptr<CCoinJoinClientManager>& clientman) {
139-
return clientman->MarkAlreadyJoinedQueueAsTried(dsq);
140-
});
141-
142-
WITH_LOCK(cs_vecqueue, vecCoinJoinQueue.push_back(dsq));
143-
}
144-
} // cs_ProcessDSQueue
145-
return ret;
146-
}
147-
148-
void CCoinJoinClientQueueManager::DoMaintenance()
149-
{
150-
if (!m_mn_sync.IsBlockchainSynced() || ShutdownRequested()) return;
151-
152-
CheckQueue();
153-
}
154-
15543
CCoinJoinClientManager::CCoinJoinClientManager(const std::shared_ptr<wallet::CWallet>& wallet,
15644
CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman,
15745
const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman,
158-
const std::unique_ptr<CCoinJoinClientQueueManager>& queueman) :
46+
CoinJoinQueueManager* queueman) :
15947
m_wallet{wallet},
16048
m_dmnman{dmnman},
16149
m_mn_metaman{mn_metaman},
@@ -192,15 +80,13 @@ void CCoinJoinClientManager::ProcessMessage(CNode& peer, CChainState& active_cha
19280

19381
CCoinJoinClientSession::CCoinJoinClientSession(const std::shared_ptr<CWallet>& wallet, CCoinJoinClientManager& clientman,
19482
CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman,
195-
const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman,
196-
const std::unique_ptr<CCoinJoinClientQueueManager>& queueman) :
83+
const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman) :
19784
m_wallet(wallet),
19885
m_clientman(clientman),
19986
m_dmnman(dmnman),
20087
m_mn_metaman(mn_metaman),
20188
m_mn_sync(mn_sync),
202-
m_isman{isman},
203-
m_queueman(queueman)
89+
m_isman{isman}
20490
{}
20591

20692
void CCoinJoinClientSession::ProcessMessage(CNode& peer, CChainState& active_chainstate, CConnman& connman, const CTxMemPool& mempool, std::string_view msg_type, CDataStream& vRecv)
@@ -1007,7 +893,7 @@ bool CCoinJoinClientManager::DoAutomaticDenominating(ChainstateManager& chainman
1007893
AssertLockNotHeld(cs_deqsessions);
1008894
LOCK(cs_deqsessions);
1009895
if (int(deqSessions.size()) < CCoinJoinClientOptions::GetSessions()) {
1010-
deqSessions.emplace_back(m_wallet, *this, m_dmnman, m_mn_metaman, m_mn_sync, m_isman, m_queueman);
896+
deqSessions.emplace_back(m_wallet, *this, m_dmnman, m_mn_metaman, m_mn_sync, m_isman);
1011897
}
1012898
for (auto& session : deqSessions) {
1013899
if (!CheckAutomaticBackup()) return false;
@@ -1075,14 +961,13 @@ static int WinnersToSkip()
1075961
bool CCoinJoinClientSession::JoinExistingQueue(CAmount nBalanceNeedsAnonymized, CConnman& connman)
1076962
{
1077963
if (!CCoinJoinClientOptions::IsEnabled()) return false;
1078-
if (m_queueman == nullptr) return false;
1079964

1080965
const auto mnList = m_dmnman.GetListAtChainTip();
1081966
const int nWeightedMnCount = mnList.GetCounts().m_valid_weighted;
1082967

1083968
// Look through the queues and see if anything matches
1084969
CCoinJoinQueue dsq;
1085-
while (m_queueman->GetQueueItemAndTry(dsq)) {
970+
while (m_clientman.GetQueueItemAndTry(dsq)) {
1086971
auto dmn = mnList.GetValidMNByCollateral(dsq.masternodeOutpoint);
1087972

1088973
if (!dmn) {
@@ -1288,6 +1173,11 @@ bool CCoinJoinClientManager::MarkAlreadyJoinedQueueAsTried(CCoinJoinQueue& dsq)
12881173
return false;
12891174
}
12901175

1176+
bool CCoinJoinClientManager::GetQueueItemAndTry(CCoinJoinQueue& dsq) const
1177+
{
1178+
return m_queueman && m_queueman->GetQueueItemAndTry(dsq);
1179+
}
1180+
12911181
bool CCoinJoinClientSession::SubmitDenominate(CConnman& connman)
12921182
{
12931183
LOCK(m_wallet->cs_wallet);
@@ -1893,59 +1783,3 @@ void CCoinJoinClientManager::GetJsonInfo(UniValue& obj) const
18931783
obj.pushKV("sessions", arrSessions);
18941784
}
18951785

1896-
CoinJoinWalletManager::CoinJoinWalletManager(ChainstateManager& chainman, CDeterministicMNManager& dmnman,
1897-
CMasternodeMetaMan& mn_metaman, const CTxMemPool& mempool,
1898-
const CMasternodeSync& mn_sync, const llmq::CInstantSendManager& isman,
1899-
const std::unique_ptr<CCoinJoinClientQueueManager>& queueman) :
1900-
m_chainman{chainman},
1901-
m_dmnman{dmnman},
1902-
m_mn_metaman{mn_metaman},
1903-
m_mempool{mempool},
1904-
m_mn_sync{mn_sync},
1905-
m_isman{isman},
1906-
m_queueman{queueman}
1907-
{
1908-
}
1909-
1910-
CoinJoinWalletManager::~CoinJoinWalletManager()
1911-
{
1912-
LOCK(cs_wallet_manager_map);
1913-
for (auto& [wallet_name, cj_man] : m_wallet_manager_map) {
1914-
cj_man.reset();
1915-
}
1916-
}
1917-
1918-
void CoinJoinWalletManager::Add(const std::shared_ptr<CWallet>& wallet)
1919-
{
1920-
LOCK(cs_wallet_manager_map);
1921-
m_wallet_manager_map.try_emplace(wallet->GetName(),
1922-
std::make_unique<CCoinJoinClientManager>(wallet, m_dmnman, m_mn_metaman, m_mn_sync,
1923-
m_isman, m_queueman));
1924-
}
1925-
1926-
void CoinJoinWalletManager::DoMaintenance(CConnman& connman)
1927-
{
1928-
LOCK(cs_wallet_manager_map);
1929-
for (auto& [_, clientman] : m_wallet_manager_map) {
1930-
clientman->DoMaintenance(m_chainman, connman, m_mempool);
1931-
}
1932-
}
1933-
1934-
void CoinJoinWalletManager::Remove(const std::string& name) {
1935-
LOCK(cs_wallet_manager_map);
1936-
m_wallet_manager_map.erase(name);
1937-
}
1938-
1939-
void CoinJoinWalletManager::Flush(const std::string& name)
1940-
{
1941-
auto clientman = Assert(Get(name));
1942-
clientman->ResetPool();
1943-
clientman->StopMixing();
1944-
}
1945-
1946-
CCoinJoinClientManager* CoinJoinWalletManager::Get(const std::string& name) const
1947-
{
1948-
LOCK(cs_wallet_manager_map);
1949-
auto it = m_wallet_manager_map.find(name);
1950-
return (it != m_wallet_manager_map.end()) ? it->second.get() : nullptr;
1951-
}

0 commit comments

Comments
 (0)