Line data Source code
1 : // Copyright (c) 2018-2025 The Dash Core developers
2 : // Distributed under the MIT software license, see the accompanying
3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 :
5 : #include <llmq/net_dkg.h>
6 :
7 : #include <active/dkgsessionhandler.h>
8 : #include <chainparams.h>
9 : #include <evo/deterministicmns.h>
10 : #include <hash.h>
11 : #include <llmq/blockprocessor.h>
12 : #include <llmq/commitment.h>
13 : #include <llmq/debug.h>
14 : #include <llmq/dkgsession.h>
15 : #include <llmq/dkgsessionmgr.h>
16 : #include <llmq/net_quorum.h>
17 : #include <llmq/options.h>
18 : #include <llmq/quorumsman.h>
19 : #include <llmq/utils.h>
20 : #include <masternode/meta.h>
21 : #include <net.h>
22 : #include <netmessagemaker.h>
23 : #include <protocol.h>
24 : #include <span.h>
25 : #include <unordered_lru_cache.h>
26 : #include <util/std23.h>
27 : #include <util/thread.h>
28 : #include <validation.h>
29 :
30 : namespace llmq {
31 :
32 : namespace {
33 : // returns a set of NodeIds which sent invalid messages
34 : template <typename Message>
35 13804 : std::unordered_set<NodeId> BatchVerifyMessageSigs(CDKGSession& session,
36 : const std::vector<std::pair<NodeId, std::shared_ptr<Message>>>& messages)
37 : {
38 13804 : if (messages.empty()) {
39 0 : return {};
40 : }
41 :
42 13804 : std::unordered_set<NodeId> ret;
43 13804 : bool revertToSingleVerification = false;
44 :
45 13804 : CBLSSignature aggSig;
46 13804 : std::vector<CBLSPublicKey> pubKeys;
47 13804 : std::vector<uint256> messageHashes;
48 13804 : Uint256HashSet messageHashesSet;
49 13804 : pubKeys.reserve(messages.size());
50 13778 : messageHashes.reserve(messages.size());
51 13779 : bool first = true;
52 51660 : for (const auto& [nodeId, msg] : messages) {
53 35476 : auto member = session.GetMember(msg->proTxHash);
54 17736 : if (!member) {
55 : // should not happen as it was verified before
56 0 : ret.emplace(nodeId);
57 0 : continue;
58 : }
59 :
60 17736 : if (first) {
61 13778 : aggSig = msg->sig;
62 13778 : } else {
63 3958 : aggSig.AggregateInsecure(msg->sig);
64 : }
65 17735 : first = false;
66 :
67 17735 : auto msgHash = msg->GetSignHash();
68 17738 : if (!messageHashesSet.emplace(msgHash).second) {
69 : // can only happen in 2 cases:
70 : // 1. Someone sent us the same message twice but with differing signature, meaning that at least one of them
71 : // must be invalid. In this case, we'd have to revert to single message verification nevertheless
72 : // 2. Someone managed to find a way to create two different binary representations of a message that deserializes
73 : // to the same object representation. This would be some form of malleability. However, this shouldn't be
74 : // possible as only deterministic/unique BLS signatures and very simple data types are involved
75 1548 : revertToSingleVerification = true;
76 1548 : break;
77 : }
78 :
79 16189 : pubKeys.emplace_back(member->dmn->pdmnState->pubKeyOperator.Get());
80 16186 : messageHashes.emplace_back(msgHash);
81 : }
82 13777 : if (!revertToSingleVerification) {
83 12229 : if (aggSig.VerifyInsecureAggregated(pubKeys, messageHashes)) {
84 : // all good
85 12231 : return ret;
86 : }
87 :
88 : // are all messages from the same node?
89 1 : bool nodeIdsAllSame = std::adjacent_find(messages.begin(), messages.end(),
90 0 : [](const auto& first, const auto& second) {
91 0 : return first.first != second.first;
92 1 : }) == messages.end();
93 :
94 : // if yes, take a short path and return a set with only him
95 1 : if (nodeIdsAllSame) {
96 1 : ret.emplace(messages[0].first);
97 1 : return ret;
98 : }
99 : // different nodes, let's figure out who are the bad ones
100 0 : }
101 :
102 8198 : for (const auto& [nodeId, msg] : messages) {
103 3325 : if (ret.count(nodeId)) {
104 0 : continue;
105 : }
106 :
107 6650 : auto member = session.GetMember(msg->proTxHash);
108 3324 : bool valid = msg->sig.VerifyInsecure(member->dmn->pdmnState->pubKeyOperator.Get(), msg->GetSignHash());
109 3325 : if (!valid) {
110 0 : ret.emplace(nodeId);
111 0 : }
112 : }
113 1548 : return ret;
114 27612 : }
115 :
116 17960 : void RelayInvToParticipants(const CDKGSession& session, const CConnman& connman, PeerManagerInternal& peerman,
117 : const CInv& inv)
118 : {
119 17960 : CDKGLogger logger(session, __func__, __LINE__);
120 17960 : std::stringstream ss;
121 17960 : const auto& relayMembers = session.RelayMembers();
122 53002 : for (const auto& r : relayMembers) {
123 35042 : ss << r.ToString().substr(0, 4) << " | ";
124 : }
125 35920 : logger.Batch("RelayInvToParticipants inv[%s] relayMembers[%d] GetNodeCount[%d] GetNetworkActive[%d] "
126 : "HasMasternodeQuorumNodes[%d] for quorumHash[%s] forMember[%s] relayMembers[%s]",
127 17960 : inv.ToString(), relayMembers.size(), connman.GetNodeCount(ConnectionDirection::Both),
128 17960 : connman.GetNetworkActive(),
129 17960 : connman.HasMasternodeQuorumNodes(session.GetType(), session.BlockIndex()->GetBlockHash()),
130 17960 : session.BlockIndex()->GetBlockHash().ToString(), session.ProTx().ToString().substr(0, 4), ss.str());
131 :
132 17960 : std::stringstream ss2;
133 114052 : connman.ForEachNode([&](const CNode* pnode) {
134 192184 : if (pnode->qwatch ||
135 96092 : (!pnode->GetVerifiedProRegTxHash().IsNull() && (relayMembers.count(pnode->GetVerifiedProRegTxHash()) != 0))) {
136 34377 : peerman.PeerPushInventory(pnode->GetId(), inv);
137 34377 : }
138 :
139 96092 : if (pnode->GetVerifiedProRegTxHash().IsNull()) {
140 17898 : logger.Batch("node[%d:%s] not mn", pnode->GetId(), pnode->m_addr_name);
141 96092 : } else if (relayMembers.count(pnode->GetVerifiedProRegTxHash()) == 0) {
142 43817 : ss2 << pnode->GetVerifiedProRegTxHash().ToString().substr(0, 4) << " | ";
143 43817 : }
144 96092 : });
145 17960 : logger.Batch("forMember[%s] NOTrelayMembers[%s]", session.ProTx().ToString().substr(0, 4), ss2.str());
146 17960 : logger.Flush();
147 17960 : }
148 :
149 : template <typename Message>
150 5159 : void EnqueueOwn(CDKGPendingMessages& pending, const Message& msg)
151 : {
152 5159 : CDataStream ds(SER_NETWORK, PROTOCOL_VERSION);
153 5159 : ds << msg;
154 5159 : auto pm = std::make_shared<CDataStream>(std::move(ds));
155 5159 : CHashWriter hw(SER_GETHASH, 0);
156 5159 : hw.write(AsWritableBytes(Span{*pm}));
157 5159 : pending.PushPendingMessage(/*from=*/-1, std::move(pm), hw.GetHash());
158 5159 : }
159 :
160 : template <typename Message>
161 138505 : bool ProcessPendingMessageBatch(const CConnman& connman, CDKGSession& session, CDKGPendingMessages& pendingMessages,
162 : PeerManagerInternal& peerman, size_t maxCount)
163 : {
164 138505 : auto msgs = pendingMessages.PopAndDeserializeMessages<Message>(maxCount);
165 138505 : if (msgs.empty()) {
166 124724 : return false;
167 : }
168 :
169 13781 : std::vector<std::pair<NodeId, std::shared_ptr<Message>>> preverifiedMessages;
170 13781 : preverifiedMessages.reserve(msgs.size());
171 :
172 31743 : for (const auto& p : msgs) {
173 17962 : const NodeId& nodeId = p.first;
174 17962 : if (!p.second) {
175 0 : LogPrint(BCLog::LLMQ_DKG, "%s -- failed to deserialize message, peer=%d\n", __func__, nodeId);
176 0 : peerman.PeerMisbehaving(nodeId, 100);
177 0 : continue;
178 : }
179 17962 : bool ban = false;
180 17962 : if (!session.PreVerifyMessage(*p.second, ban)) {
181 1 : if (ban) {
182 1 : LogPrint(BCLog::LLMQ_DKG, "%s -- banning node due to failed preverification, peer=%d\n", __func__, nodeId);
183 1 : peerman.PeerMisbehaving(nodeId, 100);
184 1 : }
185 1 : LogPrint(BCLog::LLMQ_DKG, "%s -- skipping message due to failed preverification, peer=%d\n", __func__, nodeId);
186 1 : continue;
187 : }
188 17961 : preverifiedMessages.emplace_back(p);
189 : }
190 13781 : if (preverifiedMessages.empty()) {
191 1 : return true;
192 : }
193 :
194 13780 : auto badNodes = BatchVerifyMessageSigs(session, preverifiedMessages);
195 13780 : if (!badNodes.empty()) {
196 2 : for (auto nodeId : badNodes) {
197 1 : LogPrint(BCLog::LLMQ_DKG, "%s -- failed to verify signature, peer=%d\n", __func__, nodeId);
198 1 : peerman.PeerMisbehaving(nodeId, 100);
199 : }
200 1 : }
201 :
202 31741 : for (const auto& p : preverifiedMessages) {
203 17961 : const NodeId& nodeId = p.first;
204 17961 : if (badNodes.count(nodeId)) {
205 1 : continue;
206 : }
207 17960 : const std::optional<CInv> inv = session.ReceiveMessage(*p.second);
208 17960 : if (inv) {
209 17960 : RelayInvToParticipants(session, connman, peerman, *inv);
210 17960 : }
211 : }
212 :
213 13780 : return true;
214 138505 : }
215 : } // namespace
216 :
217 :
218 18 : NetDKG::NetDKG(PeerManagerInternal* peer_manager, const CSporkManager& sporkman, CDKGSessionManager& qdkgsman,
219 : const ChainstateManager& chainman, CQuorumManager& qman, QuorumRole& role) :
220 6 : NetHandler(peer_manager),
221 6 : m_qdkgsman{qdkgsman},
222 6 : m_qman{qman},
223 6 : m_sporkman{sporkman},
224 6 : m_chainman{chainman},
225 6 : m_active{nullptr}
226 12 : {
227 42 : m_qdkgsman.InitializeHandlers([](const Consensus::LLMQParams& llmq_params,
228 : [[maybe_unused]] int quorum_idx) -> std::unique_ptr<CDKGSessionHandler> {
229 36 : return std::make_unique<CDKGSessionHandler>(llmq_params);
230 : });
231 6 : m_qman.ConnectManagers(&role, &m_qdkgsman);
232 12 : }
233 :
234 1320 : NetDKG::NetDKG(PeerManagerInternal* peer_manager, const CSporkManager& sporkman, CDKGSessionManager& qdkgsman,
235 : const ChainstateManager& chainman, bool quorums_watch, CQuorumManager& qman, QuorumRole& role,
236 : CBLSWorker& bls_worker, CDeterministicMNManager& dmnman, CMasternodeMetaMan& mn_metaman,
237 : CDKGDebugManager& dkgdbgman, CQuorumBlockProcessor& qblockman, CQuorumSnapshotManager& qsnapman,
238 : const CActiveMasternodeManager& mn_activeman, CConnman& connman) :
239 660 : NetHandler(peer_manager),
240 660 : m_qdkgsman{qdkgsman},
241 660 : m_qman{qman},
242 660 : m_sporkman{sporkman},
243 660 : m_chainman{chainman},
244 660 : m_active{std::make_unique<ActiveDKG>(ActiveDKG{dmnman, mn_metaman, dkgdbgman, qblockman, qsnapman, connman})}
245 1320 : {
246 1320 : m_qdkgsman.InitializeHandlers(
247 4620 : [&](const Consensus::LLMQParams& llmq_params, int quorum_idx) -> std::unique_ptr<ActiveDKGSessionHandler> {
248 7920 : return std::make_unique<ActiveDKGSessionHandler>(bls_worker, dmnman, mn_metaman, dkgdbgman, qdkgsman,
249 3960 : qblockman, qsnapman, mn_activeman, chainman, sporkman,
250 3960 : llmq_params, quorums_watch, quorum_idx);
251 : });
252 660 : m_qman.ConnectManagers(&role, &m_qdkgsman);
253 1320 : }
254 :
255 1998 : NetDKG::~NetDKG()
256 1332 : {
257 666 : Stop();
258 666 : m_qman.DisconnectManagers();
259 1998 : }
260 :
261 94182 : void NetDKG::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv)
262 : {
263 94182 : if (!IsQuorumDKGEnabled(m_sporkman)) return;
264 :
265 163014 : if (msg_type != NetMsgType::QCONTRIB && msg_type != NetMsgType::QCOMPLAINT && msg_type != NetMsgType::QJUSTIFICATION &&
266 80489 : msg_type != NetMsgType::QPCOMMITMENT && msg_type != NetMsgType::QWATCH) {
267 74927 : return;
268 : }
269 :
270 13130 : const bool is_masternode = m_active != nullptr;
271 :
272 13130 : if (msg_type == NetMsgType::QWATCH) {
273 30 : if (!is_masternode) {
274 : // non-masternodes should never receive this
275 9 : m_peer_manager->PeerMisbehaving(pfrom.GetId(), 10);
276 9 : return;
277 : }
278 21 : pfrom.qwatch = true;
279 21 : return;
280 : }
281 :
282 13100 : if (vRecv.empty()) {
283 0 : m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100);
284 0 : return;
285 : }
286 :
287 : Consensus::LLMQType llmqType;
288 13100 : uint256 quorumHash;
289 13100 : vRecv >> llmqType;
290 13100 : vRecv >> quorumHash;
291 13100 : vRecv.Rewind(sizeof(uint256));
292 13100 : vRecv.Rewind(sizeof(uint8_t));
293 :
294 13100 : const auto& llmq_params_opt = Params().GetLLMQ(llmqType);
295 13100 : if (!llmq_params_opt.has_value()) {
296 0 : LogPrintf("NetDKG -- invalid llmqType [%d]\n", std23::to_underlying(llmqType));
297 0 : m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100);
298 0 : return;
299 : }
300 13100 : const auto& llmq_params = llmq_params_opt.value();
301 :
302 13100 : int quorumIndex{-1};
303 : {
304 13100 : LOCK(cs_indexed_quorums_cache);
305 13100 : if (indexed_quorums_cache.empty()) {
306 394 : utils::InitQuorumsCache(indexed_quorums_cache, m_chainman.GetConsensus());
307 394 : }
308 13100 : indexed_quorums_cache[llmqType].get(quorumHash, quorumIndex);
309 13100 : }
310 :
311 13100 : if (quorumIndex == -1) {
312 4822 : const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(::cs_main,
313 : return m_chainman.m_blockman.LookupBlockIndex(quorumHash));
314 2411 : if (pQuorumBaseBlockIndex == nullptr) {
315 0 : LogPrintf("NetDKG -- unknown quorumHash %s\n", quorumHash.ToString());
316 : // NOTE: do not insta-ban for this, we might be lagging behind
317 0 : m_peer_manager->PeerMisbehaving(pfrom.GetId(), 10);
318 0 : return;
319 : }
320 2411 : if (!m_chainman.IsQuorumTypeEnabled(llmqType, pQuorumBaseBlockIndex->pprev)) {
321 0 : LogPrintf("NetDKG -- llmqType [%d] quorums aren't active\n", std23::to_underlying(llmqType));
322 0 : m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100);
323 0 : return;
324 : }
325 2411 : quorumIndex = pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval;
326 2411 : const int quorumIndexMax = IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex)
327 1182 : ? llmq_params.signingActiveQuorumCount - 1
328 : : 0;
329 2411 : if (quorumIndex > quorumIndexMax) {
330 0 : LogPrintf("NetDKG -- invalid quorumHash %s\n", quorumHash.ToString());
331 0 : m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100);
332 0 : return;
333 : }
334 2411 : }
335 :
336 13100 : int inv_type = 0;
337 13100 : if (msg_type == NetMsgType::QCONTRIB)
338 6502 : inv_type = MSG_QUORUM_CONTRIB;
339 6598 : else if (msg_type == NetMsgType::QCOMPLAINT)
340 1050 : inv_type = MSG_QUORUM_COMPLAINT;
341 5548 : else if (msg_type == NetMsgType::QJUSTIFICATION)
342 16 : inv_type = MSG_QUORUM_JUSTIFICATION;
343 5532 : else if (msg_type == NetMsgType::QPCOMMITMENT)
344 5532 : inv_type = MSG_QUORUM_PREMATURE_COMMITMENT;
345 13100 : Assume(inv_type != 0); // guarded by the early-return above
346 :
347 13100 : auto pm = std::make_shared<CDataStream>(std::move(vRecv));
348 13100 : CHashWriter hw(SER_GETHASH, 0);
349 13100 : hw.write(AsWritableBytes(Span{*pm}));
350 13100 : const uint256 hash = hw.GetHash();
351 :
352 13100 : const NodeId from = pfrom.GetId();
353 26200 : const bool dispatched = m_qdkgsman.DoForHandler({llmqType, quorumIndex}, [&](CDKGSessionHandler& handler) {
354 13100 : CDKGPendingMessages* pending = nullptr;
355 13100 : switch (inv_type) {
356 : case MSG_QUORUM_CONTRIB:
357 6502 : pending = &handler.pendingContributions;
358 6502 : break;
359 : case MSG_QUORUM_COMPLAINT:
360 1050 : pending = &handler.pendingComplaints;
361 1050 : break;
362 : case MSG_QUORUM_JUSTIFICATION:
363 16 : pending = &handler.pendingJustifications;
364 16 : break;
365 : case MSG_QUORUM_PREMATURE_COMMITMENT:
366 5532 : pending = &handler.pendingPrematureCommitments;
367 5532 : break;
368 : }
369 13100 : Assume(pending != nullptr);
370 26200 : WITH_LOCK(::cs_main, m_peer_manager->PeerEraseObjectRequest(from, CInv{static_cast<uint32_t>(inv_type), hash}));
371 13100 : pending->PushPendingMessage(from, std::move(pm), hash);
372 13100 : });
373 13100 : if (!dispatched) {
374 0 : LogPrintf("NetDKG -- no session handlers for quorumIndex [%d]\n", quorumIndex);
375 0 : m_peer_manager->PeerMisbehaving(pfrom.GetId(), 100);
376 0 : return;
377 : }
378 :
379 26200 : WITH_LOCK(cs_indexed_quorums_cache, indexed_quorums_cache[llmqType].insert(quorumHash, quorumIndex));
380 94182 : }
381 :
382 43738 : bool NetDKG::AlreadyHave(const CInv& inv)
383 : {
384 43738 : switch (inv.type) {
385 : case MSG_QUORUM_CONTRIB:
386 : case MSG_QUORUM_COMPLAINT:
387 : case MSG_QUORUM_JUSTIFICATION:
388 : case MSG_QUORUM_PREMATURE_COMMITMENT: {
389 40714 : if (!IsQuorumDKGEnabled(m_sporkman)) return false;
390 40707 : bool seen = false;
391 284949 : m_qdkgsman.ForEachHandler([&](CDKGSessionHandler& h) {
392 244242 : if (seen) return;
393 404236 : if (h.pendingContributions.HasSeen(inv.hash) || h.pendingComplaints.HasSeen(inv.hash) ||
394 199218 : h.pendingJustifications.HasSeen(inv.hash) || h.pendingPrematureCommitments.HasSeen(inv.hash)) {
395 10367 : seen = true;
396 10367 : }
397 244242 : });
398 40707 : return seen;
399 : }
400 : }
401 3024 : return false;
402 43738 : }
403 :
404 13953 : bool NetDKG::ProcessGetData(CNode& pfrom, const CInv& inv, CConnman& connman, const CNetMsgMaker& msgMaker)
405 : {
406 : // Default implementations of GetContribution and the other virtual methods
407 : // return false in observer mode; m_active is only an early exit and does
408 : // not affect logic.
409 13953 : if (m_active == nullptr) return false;
410 :
411 13953 : switch (inv.type) {
412 : case MSG_QUORUM_CONTRIB: {
413 6792 : CDKGContribution o;
414 6792 : if (m_qdkgsman.GetContribution(inv.hash, o)) {
415 6518 : connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QCONTRIB, o));
416 6518 : return true;
417 : }
418 274 : return false;
419 6792 : }
420 : case MSG_QUORUM_COMPLAINT: {
421 1214 : CDKGComplaint o;
422 1214 : if (m_qdkgsman.GetComplaint(inv.hash, o)) {
423 1057 : connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QCOMPLAINT, o));
424 1057 : return true;
425 : }
426 157 : return false;
427 1214 : }
428 : case MSG_QUORUM_JUSTIFICATION: {
429 16 : CDKGJustification o;
430 16 : if (m_qdkgsman.GetJustification(inv.hash, o)) {
431 16 : connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QJUSTIFICATION, o));
432 16 : return true;
433 : }
434 0 : return false;
435 16 : }
436 : case MSG_QUORUM_PREMATURE_COMMITMENT: {
437 5579 : CDKGPrematureCommitment o;
438 5579 : if (m_qdkgsman.GetPrematureCommitment(inv.hash, o)) {
439 5548 : connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QPCOMMITMENT, o));
440 5548 : return true;
441 : }
442 31 : return false;
443 5579 : }
444 : }
445 352 : return false;
446 13953 : }
447 :
448 666 : void NetDKG::Start()
449 : {
450 666 : if (m_active == nullptr) return;
451 660 : if (!m_phase_threads.empty()) {
452 0 : throw std::runtime_error("Tried to start PhaseHandlerThreads again.");
453 : }
454 :
455 4620 : m_qdkgsman.ForEachHandler([this](CDKGSessionHandler& base) {
456 3960 : auto& handler = dynamic_cast<ActiveDKGSessionHandler&>(base);
457 3960 : std::string thread_name = strprintf("llmq-%d-%d", std23::to_underlying(handler.params.type), handler.QuorumIndex());
458 7915 : m_phase_threads.emplace_back([this, name = std::move(thread_name), &handler] {
459 7915 : util::TraceThread(name.c_str(), [this, &handler] { PhaseHandlerThread(handler); });
460 3955 : });
461 3960 : });
462 666 : }
463 :
464 1998 : void NetDKG::Stop()
465 : {
466 1998 : Interrupt();
467 5958 : for (auto& t : m_phase_threads) {
468 3960 : if (t.joinable()) t.join();
469 : }
470 1998 : m_phase_threads.clear();
471 1998 : }
472 :
473 3330 : void NetDKG::Interrupt()
474 : {
475 3330 : if (m_active == nullptr) return;
476 23100 : m_qdkgsman.ForEachHandler([](CDKGSessionHandler& base) {
477 19800 : if (auto* handler = dynamic_cast<ActiveDKGSessionHandler*>(&base)) {
478 19800 : handler->RequestStop();
479 19800 : }
480 19800 : });
481 3330 : }
482 :
483 3960 : void NetDKG::PhaseHandlerThread(ActiveDKGSessionHandler& handler)
484 : {
485 17599 : while (!handler.IsStopRequested()) {
486 : try {
487 13637 : LogPrint(BCLog::LLMQ_DKG, "NetDKG::%s -- %s qi[%d] - starting HandleDKGRound\n", __func__,
488 : handler.params.name, handler.QuorumIndex());
489 13637 : HandleDKGRound(handler);
490 13637 : } catch (AbortPhaseException& e) {
491 9885 : m_active->dkgdbgman.MarkAborted(handler.params.type, handler.QuorumIndex());
492 9884 : LogPrint(BCLog::LLMQ_DKG, "NetDKG::%s -- %s qi[%d] - aborted current DKG session\n", __func__,
493 : handler.params.name, handler.QuorumIndex());
494 9887 : }
495 : }
496 13851 : }
497 :
498 3004 : static void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, CConnman& connman,
499 : CMasternodeMetaMan& mn_metaman, const CSporkManager& sporkman,
500 : const UtilParameters& util_params, const CDeterministicMNList& tip_mn_list,
501 : const uint256& myProTxHash)
502 : {
503 3004 : assert(mn_metaman.IsValid());
504 :
505 3004 : if (!IsQuorumPoseEnabled(llmqParams.type, sporkman)) {
506 2602 : return;
507 : }
508 :
509 402 : auto members = utils::GetAllQuorumMembers(llmqParams.type, util_params);
510 402 : auto curTime = GetTime<std::chrono::seconds>().count();
511 :
512 402 : Uint256HashSet probeConnections;
513 2070 : for (const auto& dmn : members) {
514 1668 : if (dmn->proTxHash == myProTxHash) {
515 402 : continue;
516 : }
517 1266 : auto lastOutbound = mn_metaman.GetLastOutboundSuccess(dmn->proTxHash);
518 1266 : if (curTime - lastOutbound < 10 * 60) {
519 : // avoid re-probing nodes too often
520 238 : continue;
521 : }
522 1028 : probeConnections.emplace(dmn->proTxHash);
523 : }
524 :
525 402 : if (!probeConnections.empty()) {
526 347 : if (LogAcceptDebug(BCLog::LLMQ)) {
527 347 : std::string debugMsg = strprintf("%s -- adding masternodes probes for quorum %s:\n", __func__,
528 347 : util_params.m_base_index->GetBlockHash().ToString());
529 1375 : for (const auto& c : probeConnections) {
530 1028 : auto dmn = tip_mn_list.GetValidMN(c);
531 1028 : if (!dmn) {
532 11 : debugMsg += strprintf(" %s (not in valid MN set anymore)\n", c.ToString());
533 11 : } else {
534 2034 : debugMsg += strprintf(" %s (%s)\n", c.ToString(),
535 1017 : dmn->pdmnState->netInfo->GetPrimary().ToStringAddrPort());
536 : }
537 1028 : }
538 347 : LogPrint(BCLog::NET_NETCONN, debugMsg.c_str()); /* Continued */
539 347 : }
540 347 : connman.AddPendingProbeConnections(probeConnections);
541 347 : }
542 3004 : }
543 :
544 13637 : void NetDKG::HandleDKGRound(ActiveDKGSessionHandler& handler)
545 : {
546 13637 : auto& active = *Assert(m_active);
547 :
548 14758 : handler.WaitForNextPhase(std::nullopt, QuorumPhase::Initialized);
549 :
550 11043 : handler.ClearPendingMessages();
551 11043 : uint256 curQuorumHash = handler.GetCurrentQuorumHash();
552 :
553 22086 : const CBlockIndex* pQuorumBaseBlockIndex = WITH_LOCK(::cs_main,
554 : return m_chainman.m_blockman.LookupBlockIndex(curQuorumHash));
555 :
556 11043 : if (!pQuorumBaseBlockIndex || !handler.InitNewQuorum(pQuorumBaseBlockIndex)) {
557 : // should actually never happen
558 6170 : handler.WaitForNewQuorum(curQuorumHash);
559 6170 : throw AbortPhaseException();
560 : }
561 :
562 4873 : active.dkgdbgman.MarkPhaseAdvanced(handler.params.type, handler.QuorumIndex(), QuorumPhase::Initialized);
563 :
564 4873 : auto* curSession = handler.GetCurSession();
565 4873 : if (handler.params.is_single_member()) {
566 64 : auto finalCommitment = curSession->FinalizeSingleCommitment();
567 64 : if (!finalCommitment.IsNull()) { // it can be null only if we are not member
568 33 : if (auto inv_opt = active.qblockman.AddMineableCommitment(finalCommitment); inv_opt.has_value()) {
569 33 : m_peer_manager->PeerRelayInv(inv_opt.value());
570 33 : }
571 33 : }
572 64 : handler.WaitForNextPhase(QuorumPhase::Initialized, QuorumPhase::Contribute, curQuorumHash);
573 : return;
574 64 : }
575 :
576 4809 : const auto tip_mn_list = active.dmnman.GetListAtChainTip();
577 9618 : llmq::EnsureQuorumConnections(handler.params, active.connman, m_sporkman,
578 4809 : {active.dmnman, active.qsnapman, m_chainman, pQuorumBaseBlockIndex}, tip_mn_list,
579 4809 : curSession->ProTx(), /*is_masternode=*/true, handler.QuorumsWatch());
580 4809 : if (curSession->AreWeMember()) {
581 6008 : AddQuorumProbeConnections(handler.params, active.connman, active.mn_metaman, m_sporkman,
582 3004 : {active.dmnman, active.qsnapman, m_chainman, pQuorumBaseBlockIndex}, tip_mn_list,
583 3004 : curSession->ProTx());
584 3004 : }
585 :
586 4809 : handler.WaitForNextPhase(QuorumPhase::Initialized, QuorumPhase::Contribute, curQuorumHash);
587 :
588 : // Contribute
589 8476 : auto fContributeStart = [curSession, &handler]() {
590 6840 : if (auto qc = curSession->Contribute(); qc) {
591 2602 : EnqueueOwn(handler.pendingContributions, *qc);
592 2602 : }
593 4238 : };
594 47195 : auto fContributeWait = [this, curSession, &handler, &active] {
595 85914 : return ProcessPendingMessageBatch<CDKGContribution>(active.connman, *curSession, handler.pendingContributions,
596 42957 : *m_peer_manager, 8);
597 : };
598 8476 : handler.HandlePhase(QuorumPhase::Contribute, QuorumPhase::Complain, curQuorumHash, 0.05, fContributeStart,
599 4238 : fContributeWait);
600 :
601 : // Complain
602 8078 : auto fComplainStart = [curSession, &handler, &active]() {
603 4573 : if (auto qc = curSession->VerifyAndComplain(active.connman); qc) {
604 534 : EnqueueOwn(handler.pendingComplaints, *qc);
605 534 : }
606 4039 : };
607 32293 : auto fComplainWait = [this, curSession, &handler, &active] {
608 56508 : return ProcessPendingMessageBatch<CDKGComplaint>(active.connman, *curSession, handler.pendingComplaints,
609 28254 : *m_peer_manager, 8);
610 : };
611 4039 : handler.HandlePhase(QuorumPhase::Complain, QuorumPhase::Justify, curQuorumHash, 0.05, fComplainStart, fComplainWait);
612 :
613 : // Justify
614 7876 : auto fJustifyStart = [curSession, &handler]() {
615 3946 : if (auto qj = curSession->VerifyAndJustify(); qj) {
616 8 : EnqueueOwn(handler.pendingJustifications, *qj);
617 8 : }
618 3938 : };
619 31322 : auto fJustifyWait = [this, curSession, &handler, &active] {
620 54768 : return ProcessPendingMessageBatch<CDKGJustification>(active.connman, *curSession, handler.pendingJustifications,
621 27384 : *m_peer_manager, 8);
622 : };
623 3938 : handler.HandlePhase(QuorumPhase::Justify, QuorumPhase::Commit, curQuorumHash, 0.05, fJustifyStart, fJustifyWait);
624 :
625 : // Commit
626 7712 : auto fCommitStart = [curSession, &handler]() {
627 5871 : if (auto qc = curSession->VerifyAndCommit(); qc) {
628 2015 : EnqueueOwn(handler.pendingPrematureCommitments, *qc);
629 2015 : }
630 3856 : };
631 43747 : auto fCommitWait = [this, curSession, &handler, &active] {
632 79782 : return ProcessPendingMessageBatch<CDKGPrematureCommitment>(active.connman, *curSession,
633 39891 : handler.pendingPrematureCommitments, *m_peer_manager,
634 : 8);
635 : };
636 3856 : handler.HandlePhase(QuorumPhase::Commit, QuorumPhase::Finalize, curQuorumHash, 0.1, fCommitStart, fCommitWait);
637 :
638 3727 : auto finalCommitments = curSession->FinalizeCommitments();
639 5578 : for (const auto& fqc : finalCommitments) {
640 1851 : if (auto inv_opt = active.qblockman.AddMineableCommitment(fqc); inv_opt.has_value()) {
641 1383 : m_peer_manager->PeerRelayInv(inv_opt.value());
642 1383 : }
643 : }
644 7978 : }
645 :
646 2603 : void NetDKGStub::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv)
647 : {
648 5206 : if (msg_type == NetMsgType::QCONTRIB || msg_type == NetMsgType::QCOMPLAINT || msg_type == NetMsgType::QJUSTIFICATION ||
649 2603 : msg_type == NetMsgType::QPCOMMITMENT || msg_type == NetMsgType::QWATCH) {
650 9 : m_peer_manager->PeerMisbehaving(pfrom.GetId(), 10);
651 9 : }
652 2603 : }
653 :
654 : } // namespace llmq
|