Line data Source code
1 : // Copyright (c) 2018 The Dash Core developers
2 : // Copyright (c) 2023 The PIVX Core developers
3 : // Distributed under the MIT/X11 software license, see the accompanying
4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 :
6 : #include "quorums_signing.h"
7 :
8 : #include "activemasternode.h"
9 : #include "bls/bls_batchverifier.h"
10 : #include "cxxtimer.h"
11 : #include "init.h"
12 : #include "net.h"
13 : #include "net_processing.h"
14 : #include "netmessagemaker.h"
15 : #include "quorums_signing_shares.h"
16 : #include "quorums_utils.h"
17 : #include "random.h"
18 : #include "shutdown.h"
19 : #include "tiertwo/masternode_meta_manager.h" // for g_mmetaman
20 : #include "tiertwo/net_masternodes.h"
21 : #include "validation.h"
22 :
23 : namespace llmq
24 : {
25 :
26 : std::unique_ptr<CSigSharesManager> quorumSigSharesManager{nullptr};
27 :
28 1840 : void CSigShare::UpdateKey()
29 : {
30 1840 : key.first = llmq::utils::BuildSignHash(*this);
31 1840 : key.second = quorumMember;
32 1840 : }
33 :
34 0 : std::string CSigSesAnn::ToString() const
35 : {
36 0 : return strprintf("sessionId=%d, llmqType=%d, quorumHash=%s, id=%s, msgHash=%s",
37 0 : sessionId, llmqType, quorumHash.ToString(), id.ToString(), msgHash.ToString());
38 : }
39 :
40 0 : void CSigSharesInv::Merge(const CSigSharesInv& inv2)
41 : {
42 0 : for (size_t i = 0; i < inv.size(); i++) {
43 0 : if (inv2.inv[i]) {
44 0 : inv[i] = inv2.inv[i];
45 : }
46 : }
47 0 : }
48 :
49 0 : size_t CSigSharesInv::CountSet() const
50 : {
51 0 : return (size_t)std::count(inv.begin(), inv.end(), true);
52 : }
53 :
54 0 : std::string CSigSharesInv::ToString() const
55 : {
56 0 : std::string str = "(";
57 0 : bool first = true;
58 0 : for (size_t i = 0; i < inv.size(); i++) {
59 0 : if (!inv[i]) {
60 0 : continue;
61 : }
62 :
63 0 : if (!first) {
64 0 : str += ",";
65 : }
66 0 : first = false;
67 0 : str += strprintf("%d", i);
68 : }
69 0 : str += ")";
70 0 : return str;
71 : }
72 :
73 0 : void CSigSharesInv::Init(size_t size)
74 : {
75 0 : inv.resize(size, false);
76 0 : }
77 :
78 0 : bool CSigSharesInv::IsSet(uint16_t quorumMember) const
79 : {
80 0 : assert(quorumMember < inv.size());
81 0 : return inv[quorumMember];
82 : }
83 :
84 0 : void CSigSharesInv::Set(uint16_t quorumMember, bool v)
85 : {
86 0 : assert(quorumMember < inv.size());
87 0 : inv[quorumMember] = v;
88 0 : }
89 :
90 0 : void CSigSharesInv::SetAll(bool v)
91 : {
92 0 : for (size_t i = 0; i < inv.size(); i++) {
93 0 : inv[i] = v;
94 : }
95 0 : }
96 :
97 0 : std::string CBatchedSigShares::ToInvString() const
98 : {
99 0 : CSigSharesInv inv;
100 : // we use 400 here no matter what the real size is. We don't really care about that size as we just want to call ToString()
101 0 : inv.Init(400);
102 0 : for (size_t i = 0; i < sigShares.size(); i++) {
103 0 : inv.inv[sigShares[i].first] = true;
104 : }
105 0 : return inv.ToString();
106 : }
107 :
108 : template <typename T>
109 0 : static void InitSession(CSigSharesNodeState::Session& s, const uint256& signHash, T& from)
110 : {
111 0 : const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)from.llmqType);
112 :
113 0 : s.llmqType = (Consensus::LLMQType)from.llmqType;
114 0 : s.quorumHash = from.quorumHash;
115 0 : s.id = from.id;
116 0 : s.msgHash = from.msgHash;
117 0 : s.signHash = signHash;
118 0 : s.announced.Init((size_t)params.size);
119 0 : s.requested.Init((size_t)params.size);
120 0 : s.knows.Init((size_t)params.size);
121 0 : }
122 :
123 0 : CSigSharesNodeState::Session& CSigSharesNodeState::GetOrCreateSessionFromShare(const llmq::CSigShare& sigShare)
124 : {
125 0 : auto& s = sessions[sigShare.GetSignHash()];
126 0 : if (s.announced.inv.empty()) {
127 0 : InitSession(s, sigShare.GetSignHash(), sigShare);
128 : }
129 0 : return s;
130 : }
131 :
132 0 : CSigSharesNodeState::Session& CSigSharesNodeState::GetOrCreateSessionFromAnn(const llmq::CSigSesAnn& ann)
133 : {
134 0 : auto signHash = llmq::utils::BuildSignHash((Consensus::LLMQType)ann.llmqType, ann.quorumHash, ann.id, ann.msgHash);
135 0 : auto& s = sessions[signHash];
136 0 : if (s.announced.inv.empty()) {
137 0 : InitSession(s, signHash, ann);
138 : }
139 0 : return s;
140 : }
141 :
142 0 : CSigSharesNodeState::Session* CSigSharesNodeState::GetSessionBySignHash(const uint256& signHash)
143 : {
144 0 : auto it = sessions.find(signHash);
145 0 : if (it == sessions.end()) {
146 : return nullptr;
147 : }
148 0 : return &it->second;
149 : }
150 :
151 0 : CSigSharesNodeState::Session* CSigSharesNodeState::GetSessionByRecvId(uint32_t sessionId)
152 : {
153 0 : auto it = sessionByRecvId.find(sessionId);
154 0 : if (it == sessionByRecvId.end()) {
155 : return nullptr;
156 : }
157 0 : return it->second;
158 : }
159 :
160 0 : bool CSigSharesNodeState::GetSessionInfoByRecvId(uint32_t sessionId, SessionInfo& retInfo)
161 : {
162 0 : auto s = GetSessionByRecvId(sessionId);
163 0 : if (!s) {
164 : return false;
165 : }
166 0 : retInfo.llmqType = s->llmqType;
167 0 : retInfo.quorumHash = s->quorumHash;
168 0 : retInfo.id = s->id;
169 0 : retInfo.msgHash = s->msgHash;
170 0 : retInfo.signHash = s->signHash;
171 0 : retInfo.quorum = s->quorum;
172 :
173 0 : return true;
174 : }
175 :
176 4611 : void CSigSharesNodeState::RemoveSession(const uint256& signHash)
177 : {
178 4611 : auto it = sessions.find(signHash);
179 4611 : if (it != sessions.end()) {
180 0 : sessionByRecvId.erase(it->second.recvSessionId);
181 0 : sessions.erase(it);
182 : }
183 4611 : requestedSigShares.EraseAllForSignHash(signHash);
184 4611 : pendingIncomingSigShares.EraseAllForSignHash(signHash);
185 4611 : }
186 :
187 : //////////////////////
188 :
189 475 : CSigSharesManager::CSigSharesManager()
190 : {
191 475 : interruptSigningShare.reset();
192 475 : }
193 :
194 950 : CSigSharesManager::~CSigSharesManager()
195 : {
196 950 : }
197 :
198 347 : void CSigSharesManager::StartWorkerThread()
199 : {
200 347 : workThread = std::thread(&TraceThread<std::function<void()>>, "quorum-sigshares", std::function<void()>(std::bind(&CSigSharesManager::WorkThreadMain, this)));
201 347 : }
202 :
203 357 : void CSigSharesManager::StopWorkerThread()
204 : {
205 357 : if (workThread.joinable()) {
206 347 : workThread.join();
207 : }
208 357 : }
209 :
210 347 : void CSigSharesManager::RegisterAsRecoveredSigsListener()
211 : {
212 347 : quorumSigningManager->RegisterRecoveredSigsListener(this);
213 347 : }
214 :
215 357 : void CSigSharesManager::UnregisterAsRecoveredSigsListener()
216 : {
217 357 : quorumSigningManager->UnregisterRecoveredSigsListener(this);
218 357 : }
219 :
220 475 : void CSigSharesManager::Interrupt()
221 : {
222 475 : interruptSigningShare();
223 475 : }
224 :
225 662 : void CSigSharesManager::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
226 : {
227 : // non-masternodes are not interested in sigshares
228 662 : if (!activeMasternodeManager) {
229 : return;
230 : }
231 :
232 662 : if (strCommand == NetMsgType::QSIGSHARE) {
233 1324 : std::vector<CSigShare> sigShares;
234 662 : vRecv >> sigShares;
235 :
236 662 : if (sigShares.size() > MAX_MSGS_SIG_SHARES) {
237 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- too many sigs in QSIGSHARE message. cnt=%d, max=%d, node=%d\n", __func__, sigShares.size(), MAX_MSGS_SIG_SHARES, pfrom->GetId());
238 0 : BanNode(pfrom->GetId());
239 0 : return;
240 : }
241 :
242 1534 : for (auto& sigShare : sigShares) {
243 872 : ProcessMessageSigShare(pfrom->GetId(), sigShare, connman);
244 : }
245 : }
246 :
247 662 : if (strCommand == NetMsgType::QSIGSESANN) {
248 0 : std::vector<CSigSesAnn> msgs;
249 0 : vRecv >> msgs;
250 0 : if (msgs.size() > MAX_MSGS_CNT_QSIGSESANN) {
251 0 : LogPrintf("CSigSharesManager::%s -- too many announcements in QSIGSESANN message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QSIGSESANN, pfrom->GetId());
252 0 : BanNode(pfrom->GetId());
253 0 : return;
254 : }
255 0 : for (auto& ann : msgs) {
256 0 : if (!ProcessMessageSigSesAnn(pfrom, ann, connman)) {
257 0 : BanNode(pfrom->GetId());
258 0 : return;
259 : }
260 : }
261 662 : } else if (strCommand == NetMsgType::QSIGSHARESINV) {
262 0 : std::vector<CSigSharesInv> msgs;
263 0 : vRecv >> msgs;
264 0 : if (msgs.size() > MAX_MSGS_CNT_QSIGSHARESINV) {
265 0 : LogPrintf("CSigSharesManager::%s -- too many invs in QSIGSHARESINV message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QSIGSHARESINV, pfrom->GetId());
266 0 : BanNode(pfrom->GetId());
267 0 : return;
268 : }
269 0 : for (auto& inv : msgs) {
270 0 : if (!ProcessMessageSigSharesInv(pfrom, inv, connman)) {
271 0 : BanNode(pfrom->GetId());
272 0 : return;
273 : }
274 : }
275 662 : } else if (strCommand == NetMsgType::QGETSIGSHARES) {
276 0 : std::vector<CSigSharesInv> msgs;
277 0 : vRecv >> msgs;
278 0 : if (msgs.size() > MAX_MSGS_CNT_QGETSIGSHARES) {
279 0 : LogPrintf("CSigSharesManager::%s -- too many invs in QGETSIGSHARES message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QGETSIGSHARES, pfrom->GetId());
280 0 : BanNode(pfrom->GetId());
281 0 : return;
282 : }
283 0 : for (auto& inv : msgs) {
284 0 : if (!ProcessMessageGetSigShares(pfrom, inv, connman)) {
285 0 : BanNode(pfrom->GetId());
286 0 : return;
287 : }
288 : }
289 662 : } else if (strCommand == NetMsgType::QBSIGSHARES) {
290 0 : std::vector<CBatchedSigShares> msgs;
291 0 : vRecv >> msgs;
292 0 : size_t totalSigsCount = 0;
293 0 : for (auto& bs : msgs) {
294 0 : totalSigsCount += bs.sigShares.size();
295 : }
296 0 : if (totalSigsCount > MAX_MSGS_TOTAL_BATCHED_SIGS) {
297 0 : LogPrintf("CSigSharesManager::%s -- too many sigs in QBSIGSHARES message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_TOTAL_BATCHED_SIGS, pfrom->GetId());
298 0 : BanNode(pfrom->GetId());
299 0 : return;
300 : }
301 0 : for (auto& bs : msgs) {
302 0 : if (!ProcessMessageBatchedSigShares(pfrom, bs, connman)) {
303 0 : BanNode(pfrom->GetId());
304 0 : return;
305 : }
306 : }
307 : }
308 : }
309 :
310 0 : bool CSigSharesManager::ProcessMessageSigSesAnn(CNode* pfrom, const CSigSesAnn& ann, CConnman& connman)
311 : {
312 0 : auto llmqType = (Consensus::LLMQType)ann.llmqType;
313 0 : if (!Params().GetConsensus().llmqs.count(llmqType)) {
314 0 : return false;
315 : }
316 0 : if (ann.sessionId == (uint32_t)-1 || ann.quorumHash.IsNull() || ann.id.IsNull() || ann.msgHash.IsNull()) {
317 : return false;
318 : }
319 :
320 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- ann={%s}, node=%d\n", __func__, ann.ToString(), pfrom->GetId());
321 :
322 0 : auto quorum = quorumManager->GetQuorum(llmqType, ann.quorumHash);
323 0 : if (!quorum) {
324 : // TODO should we ban here?
325 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- quorum %s not found, node=%d\n", __func__,
326 : ann.quorumHash.ToString(), pfrom->GetId());
327 0 : return true; // let's still try other announcements from the same message
328 : }
329 :
330 0 : auto signHash = llmq::utils::BuildSignHash(llmqType, ann.quorumHash, ann.id, ann.msgHash);
331 :
332 0 : LOCK(cs);
333 0 : auto& nodeState = nodeStates[pfrom->GetId()];
334 0 : auto& session = nodeState.GetOrCreateSessionFromAnn(ann);
335 0 : nodeState.sessionByRecvId.erase(session.recvSessionId);
336 0 : nodeState.sessionByRecvId.erase(ann.sessionId);
337 0 : session.recvSessionId = ann.sessionId;
338 0 : session.quorum = quorum;
339 0 : nodeState.sessionByRecvId.emplace(ann.sessionId, &session);
340 :
341 0 : return true;
342 : }
343 :
344 0 : bool CSigSharesManager::VerifySigSharesInv(NodeId from, Consensus::LLMQType llmqType, const CSigSharesInv& inv)
345 : {
346 0 : size_t quorumSize = (size_t)Params().GetConsensus().llmqs.at(llmqType).size;
347 :
348 0 : if (inv.inv.size() != quorumSize) {
349 0 : return false;
350 : }
351 : return true;
352 : }
353 :
354 0 : bool CSigSharesManager::ProcessMessageSigSharesInv(CNode* pfrom, const CSigSharesInv& inv, CConnman& connman)
355 : {
356 0 : CSigSharesNodeState::SessionInfo sessionInfo;
357 0 : if (!GetSessionInfoByRecvId(pfrom->GetId(), inv.sessionId, sessionInfo)) {
358 : return true;
359 : }
360 :
361 0 : if (!VerifySigSharesInv(pfrom->GetId(), sessionInfo.llmqType, inv)) {
362 : return false;
363 : }
364 :
365 : // TODO for PoSe, we should consider propagating shares even if we already have a recovered sig
366 0 : if (quorumSigningManager->HasRecoveredSigForSession(sessionInfo.signHash)) {
367 : return true;
368 : }
369 :
370 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, inv={%s}, node=%d\n", __func__,
371 : sessionInfo.signHash.ToString(), inv.ToString(), pfrom->GetId());
372 :
373 0 : if (sessionInfo.quorum->quorumVvec == nullptr) {
374 : // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG
375 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, not requesting sig shares. node=%d\n", __func__,
376 : sessionInfo.quorumHash.ToString(), pfrom->GetId());
377 0 : return true;
378 : }
379 :
380 0 : LOCK(cs);
381 0 : auto& nodeState = nodeStates[pfrom->GetId()];
382 0 : auto session = nodeState.GetSessionByRecvId(inv.sessionId);
383 0 : if (!session) {
384 : return true;
385 : }
386 0 : session->announced.Merge(inv);
387 0 : session->knows.Merge(inv);
388 0 : return true;
389 : }
390 :
391 0 : bool CSigSharesManager::ProcessMessageGetSigShares(CNode* pfrom, const CSigSharesInv& inv, CConnman& connman)
392 : {
393 0 : CSigSharesNodeState::SessionInfo sessionInfo;
394 0 : if (!GetSessionInfoByRecvId(pfrom->GetId(), inv.sessionId, sessionInfo)) {
395 : return true;
396 : }
397 :
398 0 : if (!VerifySigSharesInv(pfrom->GetId(), sessionInfo.llmqType, inv)) {
399 : return false;
400 : }
401 :
402 : // TODO for PoSe, we should consider propagating shares even if we already have a recovered sig
403 0 : if (quorumSigningManager->HasRecoveredSigForSession(sessionInfo.signHash)) {
404 : return true;
405 : }
406 :
407 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, inv={%s}, node=%d\n", __func__,
408 : sessionInfo.signHash.ToString(), inv.ToString(), pfrom->GetId());
409 :
410 0 : LOCK(cs);
411 0 : auto& nodeState = nodeStates[pfrom->GetId()];
412 0 : auto session = nodeState.GetSessionByRecvId(inv.sessionId);
413 0 : if (!session) {
414 : return true;
415 : }
416 0 : session->requested.Merge(inv);
417 0 : session->knows.Merge(inv);
418 0 : return true;
419 : }
420 :
421 0 : bool CSigSharesManager::ProcessMessageBatchedSigShares(CNode* pfrom, const CBatchedSigShares& batchedSigShares, CConnman& connman)
422 : {
423 0 : CSigSharesNodeState::SessionInfo sessionInfo;
424 0 : if (!GetSessionInfoByRecvId(pfrom->GetId(), batchedSigShares.sessionId, sessionInfo)) {
425 : return true;
426 : }
427 :
428 0 : bool ban = false;
429 0 : if (!PreVerifyBatchedSigShares(pfrom->GetId(), sessionInfo, batchedSigShares, ban)) {
430 0 : return !ban;
431 : }
432 :
433 0 : std::vector<CSigShare> sigShares;
434 0 : sigShares.reserve(batchedSigShares.sigShares.size());
435 :
436 0 : {
437 0 : LOCK(cs);
438 0 : auto& nodeState = nodeStates[pfrom->GetId()];
439 :
440 0 : for (size_t i = 0; i < batchedSigShares.sigShares.size(); i++) {
441 0 : CSigShare sigShare = RebuildSigShare(sessionInfo, batchedSigShares, i);
442 0 : nodeState.requestedSigShares.Erase(sigShare.GetKey());
443 :
444 : // TODO track invalid sig shares received for PoSe?
445 : // It's important to only skip seen *valid* sig shares here. If a node sends us a
446 : // batch of mostly valid sig shares with a single invalid one and thus batched
447 : // verification fails, we'd skip the valid ones in the future if received from other nodes
448 0 : if (this->sigShares.Has(sigShare.GetKey())) {
449 0 : continue;
450 : }
451 :
452 : // TODO for PoSe, we should consider propagating shares even if we already have a recovered sig
453 0 : if (quorumSigningManager->HasRecoveredSigForId((Consensus::LLMQType)sigShare.llmqType, sigShare.id)) {
454 0 : continue;
455 : }
456 :
457 0 : sigShares.emplace_back(sigShare);
458 : }
459 : }
460 :
461 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, shares=%d, new=%d, inv={%s}, node=%d\n", __func__,
462 : sessionInfo.signHash.ToString(), batchedSigShares.sigShares.size(), sigShares.size(), batchedSigShares.ToInvString(), pfrom->GetId());
463 :
464 0 : if (sigShares.empty()) {
465 : return true;
466 : }
467 :
468 0 : LOCK(cs);
469 0 : auto& nodeState = nodeStates[pfrom->GetId()];
470 0 : for (auto& s : sigShares) {
471 0 : nodeState.pendingIncomingSigShares.Add(s.GetKey(), s);
472 : }
473 0 : return true;
474 : }
475 :
476 872 : void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& sigShare, CConnman& connman)
477 : {
478 1484 : auto quorum = quorumManager->GetQuorum((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash);
479 872 : if (!quorum) {
480 260 : return;
481 : }
482 872 : if (!llmq::utils::IsQuorumActive((Consensus::LLMQType)sigShare.llmqType, quorum->qc.quorumHash)) {
483 : // quorum is too old
484 : return;
485 : }
486 872 : if (!quorum->IsMember(activeMasternodeManager->GetProTx())) {
487 : // we're not a member so we can't verify it (we actually shouldn't have received it)
488 : return;
489 : }
490 872 : if (quorum->quorumVvec == nullptr) {
491 : // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG
492 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible. node=%d\n", __func__,
493 : quorum->qc.quorumHash.ToString(), fromId);
494 0 : return;
495 : }
496 :
497 872 : if (sigShare.quorumMember >= quorum->members.size()) {
498 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- quorumMember out of bounds\n", __func__);
499 0 : BanNode(fromId);
500 : return;
501 : }
502 872 : if (!quorum->qc.validMembers[sigShare.quorumMember]) {
503 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- quorumMember not valid\n", __func__);
504 0 : BanNode(fromId);
505 : return;
506 : }
507 :
508 872 : {
509 872 : LOCK(cs);
510 :
511 872 : if (sigShares.Has(sigShare.GetKey())) {
512 260 : return;
513 : }
514 :
515 872 : if (quorumSigningManager->HasRecoveredSigForId((Consensus::LLMQType)sigShare.llmqType, sigShare.id)) {
516 : return;
517 : }
518 :
519 612 : auto& nodeState = nodeStates[fromId];
520 612 : nodeState.pendingIncomingSigShares.Add(sigShare.GetKey(), sigShare);
521 : }
522 :
523 2448 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, id=%s, msgHash=%s, member=%d, node=%d\n", __func__,
524 : sigShare.GetSignHash().ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), sigShare.quorumMember, fromId);
525 : }
526 :
527 0 : bool CSigSharesManager::PreVerifyBatchedSigShares(NodeId nodeId, const CSigSharesNodeState::SessionInfo& session, const CBatchedSigShares& batchedSigShares, bool& retBan)
528 : {
529 0 : retBan = false;
530 :
531 0 : if (!llmq::utils::IsQuorumActive(session.llmqType, session.quorum->qc.quorumHash)) {
532 : // quorum is too old
533 : return false;
534 : }
535 0 : if (!session.quorum->IsMember(activeMasternodeManager->GetProTx())) {
536 : // we're not a member so we can't verify it (we actually shouldn't have received it)
537 : return false;
538 : }
539 0 : if (session.quorum->quorumVvec == nullptr) {
540 : // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG
541 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible. node=%d\n", __func__,
542 : session.quorumHash.ToString(), nodeId);
543 0 : return false;
544 : }
545 :
546 0 : std::unordered_set<uint16_t> dupMembers;
547 :
548 0 : for (size_t i = 0; i < batchedSigShares.sigShares.size(); i++) {
549 0 : auto quorumMember = batchedSigShares.sigShares[i].first;
550 0 : if (!dupMembers.emplace(quorumMember).second) {
551 0 : retBan = true;
552 0 : return false;
553 : }
554 :
555 0 : if (quorumMember >= session.quorum->members.size()) {
556 0 : LogPrintf("CSigSharesManager::%s -- quorumMember out of bounds\n", __func__);
557 0 : retBan = true;
558 0 : return false;
559 : }
560 0 : if (!session.quorum->qc.validMembers[quorumMember]) {
561 0 : LogPrintf("CSigSharesManager::%s -- quorumMember not valid\n", __func__);
562 0 : retBan = true;
563 0 : return false;
564 : }
565 : }
566 : return true;
567 : }
568 :
569 155386 : void CSigSharesManager::CollectPendingSigSharesToVerify(
570 : size_t maxUniqueSessions,
571 : std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
572 : std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums)
573 : {
574 155386 : {
575 155386 : LOCK(cs);
576 155386 : if (nodeStates.empty()) {
577 155031 : return;
578 : }
579 :
580 : // This will iterate node states in random order and pick one sig share at a time. This avoids processing
581 : // of large batches at once from the same node while other nodes also provided shares. If we wouldn't do this,
582 : // other nodes would be able to poison us with a large batch with N-1 valid shares and the last one being
583 : // invalid, making batch verification fail and revert to per-share verification, which in turn would slow down
584 : // the whole verification process
585 :
586 10568 : std::unordered_set<std::pair<NodeId, uint256>, StaticSaltedHasher> uniqueSignHashes;
587 24179 : llmq::utils::IterateNodesRandom(nodeStates, [&]() { return uniqueSignHashes.size() < maxUniqueSessions; }, [&](NodeId nodeId, CSigSharesNodeState& ns) {
588 24179 : if (ns.pendingIncomingSigShares.Empty()) {
589 : return false;
590 : }
591 593 : auto& sigShare = *ns.pendingIncomingSigShares.GetFirst();
592 :
593 593 : bool alreadyHave = this->sigShares.Has(sigShare.GetKey());
594 593 : if (!alreadyHave) {
595 593 : uniqueSignHashes.emplace(nodeId, sigShare.GetSignHash());
596 593 : retSigShares[nodeId].emplace_back(sigShare);
597 : }
598 593 : ns.pendingIncomingSigShares.Erase(sigShare.GetKey());
599 10806 : return !ns.pendingIncomingSigShares.Empty(); }, rnd);
600 :
601 10213 : if (retSigShares.empty()) {
602 164889 : return;
603 : }
604 : }
605 :
606 355 : {
607 710 : LOCK(cs_main);
608 :
609 : // For the convenience of the caller, also build a map of quorumHash -> quorum
610 :
611 812 : for (auto& p : retSigShares) {
612 1050 : for (auto& sigShare : p.second) {
613 593 : auto llmqType = (Consensus::LLMQType)sigShare.llmqType;
614 :
615 593 : auto k = std::make_pair(llmqType, sigShare.quorumHash);
616 593 : if (retQuorums.count(k)) {
617 213 : continue;
618 : }
619 :
620 760 : CQuorumCPtr quorum = quorumManager->GetQuorum(llmqType, sigShare.quorumHash);
621 380 : assert(quorum != nullptr);
622 380 : retQuorums.emplace(k, quorum);
623 : }
624 : }
625 : }
626 : }
627 :
628 155386 : bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman)
629 : {
630 310772 : std::unordered_map<NodeId, std::vector<CSigShare>> sigSharesByNodes;
631 155386 : std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher> quorums;
632 :
633 155386 : CollectPendingSigSharesToVerify(32, sigSharesByNodes, quorums);
634 155386 : if (sigSharesByNodes.empty()) {
635 : return false;
636 : }
637 :
638 : // It's ok to perform insecure batched verification here as we verify against the quorum public key shares,
639 : // which are not craftable by individual entities, making the rogue public key attack impossible
640 355 : CBLSBatchVerifier<NodeId, SigShareKey> batchVerifier(false, true);
641 :
642 355 : cxxtimer::Timer prepareTimer(true);
643 355 : size_t verifyCount = 0;
644 812 : for (auto& p : sigSharesByNodes) {
645 457 : auto nodeId = p.first;
646 457 : auto& v = p.second;
647 :
648 1050 : for (auto& sigShare : v) {
649 593 : if (quorumSigningManager->HasRecoveredSigForId((Consensus::LLMQType)sigShare.llmqType, sigShare.id)) {
650 0 : continue;
651 : }
652 :
653 : // we didn't check this earlier because we use a lazy BLS signature and tried to avoid doing the expensive
654 : // deserialization in the message thread
655 593 : if (!sigShare.sigShare.Get().IsValid()) {
656 0 : BanNode(nodeId);
657 : // don't process any additional shares from this node
658 0 : break;
659 : }
660 :
661 1186 : auto quorum = quorums.at(std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash));
662 593 : auto pubKeyShare = quorum->GetPubKeyShare(sigShare.quorumMember);
663 :
664 593 : if (!pubKeyShare.IsValid()) {
665 : // this should really not happen (we already ensured we have the quorum vvec,
666 : // so we should also be able to create all pubkey shares)
667 0 : LogPrintf("CSigSharesManager::%s -- pubKeyShare is invalid, which should not be possible here.\n", __func__);
668 0 : assert(false);
669 : }
670 :
671 593 : batchVerifier.PushMessage(nodeId, sigShare.GetKey(), sigShare.GetSignHash(), sigShare.sigShare.Get(), pubKeyShare);
672 593 : verifyCount++;
673 : }
674 : }
675 355 : prepareTimer.stop();
676 :
677 710 : cxxtimer::Timer verifyTimer(true);
678 355 : batchVerifier.Verify();
679 355 : verifyTimer.stop();
680 :
681 355 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- verified sig shares. count=%d, pt=%d, vt=%d, nodes=%d\n", __func__, verifyCount, prepareTimer.count(), verifyTimer.count(), sigSharesByNodes.size());
682 :
683 812 : for (auto& p : sigSharesByNodes) {
684 457 : auto nodeId = p.first;
685 457 : auto& v = p.second;
686 :
687 457 : if (batchVerifier.badSources.count(nodeId)) {
688 0 : LogPrintf("CSigSharesManager::%s -- invalid sig shares from other node, banning peer=%d\n",
689 : __func__, nodeId);
690 : // this will also cause re-requesting of the shares that were sent by this node
691 0 : BanNode(nodeId);
692 0 : continue;
693 : }
694 :
695 457 : ProcessPendingSigSharesFromNode(nodeId, v, quorums, connman);
696 : }
697 :
698 355 : return true;
699 : }
700 :
701 : // It's ensured that no duplicates are passed to this method
702 457 : void CSigSharesManager::ProcessPendingSigSharesFromNode(NodeId nodeId,
703 : const std::vector<CSigShare>& sigShares,
704 : const std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& quorums,
705 : CConnman& connman)
706 : {
707 457 : LOCK(cs);
708 457 : auto& nodeState = nodeStates[nodeId];
709 :
710 914 : cxxtimer::Timer t(true);
711 1050 : for (auto& sigShare : sigShares) {
712 593 : auto quorumKey = std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash);
713 593 : ProcessSigShare(nodeId, sigShare, connman, quorums.at(quorumKey));
714 : }
715 457 : t.stop();
716 :
717 457 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- processed sigShare batch. shares=%d, time=%d, node=%d\n", __func__,
718 : sigShares.size(), t.count(), nodeId);
719 457 : }
720 :
721 : // sig shares are already verified when entering this method
722 1561 : void CSigSharesManager::ProcessSigShare(NodeId nodeId, const CSigShare& sigShare, CConnman& connman, const CQuorumCPtr& quorum)
723 : {
724 1561 : auto llmqType = quorum->params.type;
725 :
726 1561 : bool canTryRecovery = false;
727 :
728 : // prepare node set for direct-push in case this is our sig share
729 3053 : std::set<NodeId> quorumNodes;
730 :
731 1561 : if (quorumSigningManager->HasRecoveredSigForId(llmqType, sigShare.id)) {
732 69 : return;
733 : }
734 :
735 1492 : {
736 1492 : LOCK(cs);
737 :
738 1492 : if (!sigShares.Add(sigShare.GetKey(), sigShare)) {
739 0 : return;
740 : }
741 1492 : sigSharesToAnnounce.Add(sigShare.GetKey(), true);
742 :
743 : // Update the time we've seen the last sigShare
744 1492 : timeSeenForSessions[sigShare.GetSignHash()] = GetAdjustedTime();
745 :
746 : // TODO: unreachable
747 1492 : if (!quorumNodes.empty()) {
748 : // don't announce and wait for other nodes to request this share and directly send it to them
749 : // there is no way the other nodes know about this share as this is the one created on this node
750 0 : for (auto otherNodeId : quorumNodes) {
751 0 : auto& nodeState = nodeStates[otherNodeId];
752 0 : auto& session = nodeState.GetOrCreateSessionFromShare(sigShare);
753 0 : session.quorum = quorum;
754 0 : session.requested.Set(sigShare.quorumMember, true);
755 0 : session.knows.Set(sigShare.quorumMember, true);
756 : }
757 : }
758 :
759 1492 : size_t sigShareCount = sigShares.CountForSignHash(sigShare.GetSignHash());
760 1492 : if (sigShareCount >= quorum->params.threshold) {
761 385 : canTryRecovery = true;
762 : }
763 : }
764 :
765 1492 : if (canTryRecovery) {
766 385 : TryRecoverSig(quorum, sigShare.id, sigShare.msgHash, connman);
767 : }
768 : }
769 :
770 385 : void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash, CConnman& connman)
771 : {
772 385 : if (quorumSigningManager->HasRecoveredSigForId(quorum->params.type, id)) {
773 0 : return;
774 : }
775 :
776 770 : std::vector<CBLSSignature> sigSharesForRecovery;
777 385 : std::vector<CBLSId> idsForRecovery;
778 385 : {
779 385 : LOCK(cs);
780 :
781 385 : auto k = std::make_pair(quorum->params.type, id);
782 :
783 385 : auto signHash = llmq::utils::BuildSignHash(quorum->params.type, quorum->qc.quorumHash, id, msgHash);
784 385 : auto sigShares = this->sigShares.GetAllForSignHash(signHash);
785 385 : if (!sigShares) {
786 0 : return;
787 : }
788 :
789 385 : sigSharesForRecovery.reserve((size_t)quorum->params.threshold);
790 385 : idsForRecovery.reserve((size_t)quorum->params.threshold);
791 1155 : for (auto it = sigShares->begin(); it != sigShares->end() && sigSharesForRecovery.size() < quorum->params.threshold; ++it) {
792 770 : auto& sigShare = it->second;
793 770 : sigSharesForRecovery.emplace_back(sigShare.sigShare.Get());
794 770 : idsForRecovery.emplace_back(CBLSId(quorum->members[sigShare.quorumMember]->proTxHash));
795 : }
796 :
797 : // check if we can recover the final signature
798 385 : if (sigSharesForRecovery.size() < quorum->params.threshold) {
799 : return;
800 : }
801 : }
802 :
803 : // now recover it
804 770 : cxxtimer::Timer t(true);
805 385 : CBLSSignature recoveredSig;
806 385 : if (!recoveredSig.Recover(sigSharesForRecovery, idsForRecovery)) {
807 0 : LogPrintf("CSigSharesManager::%s -- failed to recover signature. id=%s, msgHash=%s, time=%d\n", __func__,
808 0 : id.ToString(), msgHash.ToString(), t.count());
809 0 : return;
810 : }
811 :
812 1155 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- recovered signature. id=%s, msgHash=%s, time=%d\n", __func__,
813 : id.ToString(), msgHash.ToString(), t.count());
814 :
815 770 : CRecoveredSig rs;
816 385 : rs.llmqType = quorum->params.type;
817 385 : rs.quorumHash = quorum->qc.quorumHash;
818 385 : rs.id = id;
819 385 : rs.msgHash = msgHash;
820 385 : rs.sig.Set(recoveredSig);
821 385 : rs.UpdateHash();
822 :
823 : // There should actually be no need to verify the self-recovered signatures as it should always succeed. Let's
824 : // however still verify it from time to time, so that we have a chance to catch bugs. We do only this sporadic
825 : // verification because this is unbatched and thus slow verification that happens here.
826 385 : if (((recoveredSigsCounter++) % 100) == 0) {
827 18 : auto signHash = llmq::utils::BuildSignHash(rs);
828 18 : bool valid = recoveredSig.VerifyInsecure(quorum->qc.quorumPublicKey, signHash);
829 18 : if (!valid) {
830 : // this should really not happen as we have verified all signature shares before
831 0 : LogPrintf("CSigSharesManager::%s -- own recovered signature is invalid. id=%s, msgHash=%s\n", __func__,
832 0 : id.ToString(), msgHash.ToString());
833 0 : return;
834 : }
835 : }
836 :
837 385 : quorumSigningManager->ProcessRecoveredSig(-1, rs, quorum, connman);
838 : }
839 :
840 1218 : CDeterministicMNCPtr CSigSharesManager::SelectMemberForRecovery(const CQuorumCPtr& quorum, const uint256& id, int attempt)
841 : {
842 1218 : assert(attempt < quorum->members.size());
843 :
844 1218 : std::vector<std::pair<uint256, CDeterministicMNCPtr>> v;
845 1218 : v.reserve(quorum->members.size());
846 4872 : for (const auto& dmn : quorum->members) {
847 3654 : auto h = ::SerializeHash(std::make_pair(dmn->proTxHash, id));
848 3654 : v.emplace_back(h, dmn);
849 : }
850 1218 : std::sort(v.begin(), v.end());
851 :
852 1218 : return v[attempt].second;
853 : }
854 :
855 : // TODO unused
856 0 : void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToRequest)
857 : {
858 0 : AssertLockHeld(cs);
859 :
860 0 : int64_t now = GetAdjustedTime();
861 0 : const size_t maxRequestsForNode = 32;
862 :
863 : // avoid requesting from same nodes all the time
864 0 : std::vector<NodeId> shuffledNodeIds;
865 0 : shuffledNodeIds.reserve(nodeStates.size());
866 0 : for (auto& p : nodeStates) {
867 0 : if (p.second.sessions.empty()) {
868 0 : continue;
869 : }
870 0 : shuffledNodeIds.emplace_back(p.first);
871 : }
872 0 : Shuffle(shuffledNodeIds.begin(), shuffledNodeIds.end(), rnd);
873 :
874 0 : for (auto& nodeId : shuffledNodeIds) {
875 0 : auto& nodeState = nodeStates[nodeId];
876 :
877 0 : if (nodeState.banned) {
878 0 : continue;
879 : }
880 :
881 0 : nodeState.requestedSigShares.EraseIf([&](const SigShareKey& k, int64_t t) {
882 0 : if (now - t >= SIG_SHARE_REQUEST_TIMEOUT) {
883 : // timeout while waiting for this one, so retry it with another node
884 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::CollectSigSharesToRequest -- timeout while waiting for %s-%d, node=%d\n",
885 : k.first.ToString(), k.second, nodeId);
886 0 : return true;
887 : }
888 : return false;
889 : });
890 :
891 0 : decltype(sigSharesToRequest.begin()->second)* invMap = nullptr;
892 :
893 0 : for (auto& p2 : nodeState.sessions) {
894 0 : auto& signHash = p2.first;
895 0 : auto& session = p2.second;
896 :
897 0 : if (quorumSigningManager->HasRecoveredSigForSession(signHash)) {
898 0 : continue;
899 : }
900 :
901 0 : for (size_t i = 0; i < session.announced.inv.size(); i++) {
902 0 : if (!session.announced.inv[i]) {
903 0 : continue;
904 : }
905 0 : auto k = std::make_pair(signHash, (uint16_t)i);
906 0 : if (sigShares.Has(k)) {
907 : // we already have it
908 0 : session.announced.inv[i] = false;
909 0 : continue;
910 : }
911 0 : if (nodeState.requestedSigShares.Size() >= maxRequestsForNode) {
912 : // too many pending requests for this node
913 : break;
914 : }
915 0 : auto p = sigSharesRequested.Get(k);
916 0 : if (p) {
917 0 : if (now - p->second >= SIG_SHARE_REQUEST_TIMEOUT && nodeId != p->first) {
918 : // other node timed out, re-request from this node
919 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- other node timeout while waiting for %s-%d, re-request from=%d, node=%d\n", __func__,
920 : k.first.ToString(), k.second, nodeId, p->first);
921 : } else {
922 0 : continue;
923 : }
924 : }
925 : // if we got this far we should do a request
926 :
927 : // track when we initiated the request so that we can detect timeouts
928 0 : nodeState.requestedSigShares.Add(k, now);
929 :
930 : // don't request it from other nodes until a timeout happens
931 0 : auto& r = sigSharesRequested.GetOrAdd(k);
932 0 : r.first = nodeId;
933 0 : r.second = now;
934 :
935 0 : if (!invMap) {
936 0 : invMap = &sigSharesToRequest[nodeId];
937 : }
938 0 : auto& inv = (*invMap)[signHash];
939 0 : if (inv.inv.empty()) {
940 0 : const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)session.llmqType);
941 0 : inv.Init((size_t)params.size);
942 : }
943 0 : inv.inv[k.second] = true;
944 :
945 : // don't request it again from this node
946 0 : session.announced.inv[i] = false;
947 : }
948 : }
949 : }
950 0 : }
951 :
952 : // TODO: unused
953 0 : void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares, StaticSaltedHasher>>& sigSharesToSend)
954 : {
955 0 : AssertLockHeld(cs);
956 :
957 0 : for (auto& p : nodeStates) {
958 0 : auto nodeId = p.first;
959 0 : auto& nodeState = p.second;
960 :
961 0 : if (nodeState.banned) {
962 0 : continue;
963 : }
964 :
965 0 : decltype(sigSharesToSend.begin()->second)* sigSharesToSend2 = nullptr;
966 :
967 0 : for (auto& p2 : nodeState.sessions) {
968 0 : auto& signHash = p2.first;
969 0 : auto& session = p2.second;
970 :
971 0 : if (quorumSigningManager->HasRecoveredSigForSession(signHash)) {
972 0 : continue;
973 : }
974 :
975 0 : CBatchedSigShares batchedSigShares;
976 :
977 0 : for (size_t i = 0; i < session.requested.inv.size(); i++) {
978 0 : if (!session.requested.inv[i]) {
979 0 : continue;
980 : }
981 0 : session.requested.inv[i] = false;
982 :
983 0 : auto k = std::make_pair(signHash, (uint16_t)i);
984 0 : const CSigShare* sigShare = sigShares.Get(k);
985 0 : if (!sigShare) {
986 : // he requested something we don'have
987 0 : session.requested.inv[i] = false;
988 0 : continue;
989 : }
990 :
991 0 : batchedSigShares.sigShares.emplace_back((uint16_t)i, sigShare->sigShare);
992 : }
993 :
994 0 : if (!batchedSigShares.sigShares.empty()) {
995 0 : if (sigSharesToSend2 == nullptr) {
996 : // only create the map if we actually add a batched sig
997 0 : sigSharesToSend2 = &sigSharesToSend[nodeId];
998 : }
999 0 : (*sigSharesToSend2).emplace(signHash, std::move(batchedSigShares));
1000 : }
1001 : }
1002 : }
1003 0 : }
1004 :
1005 83875 : void CSigSharesManager::CollectSigSharesToSend(std::unordered_map<NodeId, std::vector<CSigShare>>& sigSharesToSend, const std::vector<CNode*>& vNodes)
1006 : {
1007 83875 : AssertLockHeld(cs);
1008 :
1009 83875 : std::unordered_map<uint256, CNode*> proTxToNode;
1010 486588 : for (const auto& pnode : vNodes) {
1011 805426 : if (pnode->verifiedProRegTxHash.IsNull()) {
1012 377385 : continue;
1013 : }
1014 402713 : proTxToNode.emplace(pnode->verifiedProRegTxHash, pnode);
1015 : }
1016 :
1017 83875 : auto curTime = GetTime<std::chrono::milliseconds>().count();
1018 :
1019 121868 : for (auto& p : signedSessions) {
1020 37993 : if (p.second.attempt >= p.second.quorum->params.recoveryMembers) {
1021 31467 : continue;
1022 : }
1023 :
1024 6526 : if (curTime >= p.second.nextAttemptTime) {
1025 1218 : int64_t waitTime = exp2(p.second.attempt) * EXP_SEND_FOR_RECOVERY_TIMEOUT;
1026 1218 : waitTime = std::min(MAX_SEND_FOR_RECOVERY_TIMEOUT, waitTime);
1027 1218 : p.second.nextAttemptTime = curTime + waitTime;
1028 2090 : auto dmn = SelectMemberForRecovery(p.second.quorum, p.second.sigShare.id, p.second.attempt);
1029 1218 : p.second.attempt++;
1030 :
1031 3654 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, sending to %s, attempt=%d\n", __func__,
1032 : p.second.sigShare.GetSignHash().ToString(), dmn->proTxHash.ToString(), p.second.attempt);
1033 :
1034 1218 : auto it = proTxToNode.find(dmn->proTxHash);
1035 1218 : if (it == proTxToNode.end()) {
1036 692 : continue;
1037 : }
1038 :
1039 872 : auto& m = sigSharesToSend[it->second->GetId()];
1040 872 : m.emplace_back(p.second.sigShare);
1041 : }
1042 : }
1043 83875 : }
1044 :
1045 : // TODO unused
1046 0 : void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>>& sigSharesToAnnounce)
1047 : {
1048 0 : AssertLockHeld(cs);
1049 :
1050 0 : std::unordered_map<std::pair<Consensus::LLMQType, uint256>, std::unordered_set<NodeId>, StaticSaltedHasher> quorumNodesMap;
1051 :
1052 0 : this->sigSharesToAnnounce.ForEach([&](const SigShareKey& sigShareKey, bool) {
1053 0 : auto& signHash = sigShareKey.first;
1054 0 : auto quorumMember = sigShareKey.second;
1055 0 : const CSigShare* sigShare = sigShares.Get(sigShareKey);
1056 0 : if (!sigShare) {
1057 0 : return;
1058 : }
1059 :
1060 : // announce to the nodes which we know through the intra-quorum-communication system
1061 0 : auto quorumKey = std::make_pair((Consensus::LLMQType)sigShare->llmqType, sigShare->quorumHash);
1062 0 : auto it = quorumNodesMap.find(quorumKey);
1063 0 : if (it == quorumNodesMap.end()) {
1064 0 : auto nodeIds = g_connman->GetTierTwoConnMan()->getQuorumNodes(quorumKey.first, quorumKey.second);
1065 0 : it = quorumNodesMap.emplace(std::piecewise_construct, std::forward_as_tuple(quorumKey), std::forward_as_tuple(nodeIds.begin(), nodeIds.end())).first;
1066 : }
1067 :
1068 0 : auto& quorumNodes = it->second;
1069 :
1070 0 : for (auto& nodeId : quorumNodes) {
1071 0 : auto& nodeState = nodeStates[nodeId];
1072 :
1073 0 : if (nodeState.banned) {
1074 0 : continue;
1075 : }
1076 :
1077 0 : auto& session = nodeState.GetOrCreateSessionFromShare(*sigShare);
1078 :
1079 0 : if (session.knows.inv[quorumMember]) {
1080 : // he already knows that one
1081 0 : continue;
1082 : }
1083 :
1084 0 : auto& inv = sigSharesToAnnounce[nodeId][signHash];
1085 0 : if (inv.inv.empty()) {
1086 0 : const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)sigShare->llmqType);
1087 0 : inv.Init((size_t)params.size);
1088 : }
1089 0 : inv.inv[quorumMember] = true;
1090 0 : session.knows.inv[quorumMember] = true;
1091 : }
1092 : });
1093 :
1094 : // don't announce these anymore
1095 0 : this->sigSharesToAnnounce.Clear();
1096 0 : }
1097 :
1098 83875 : bool CSigSharesManager::SendMessages()
1099 : {
1100 83875 : std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>> sigSharesToRequest;
1101 83875 : std::unordered_map<NodeId, std::unordered_map<uint256, CBatchedSigShares, StaticSaltedHasher>> sigShareBatchesToSend;
1102 83875 : std::unordered_map<NodeId, std::vector<CSigShare>> sigSharesToSend;
1103 83875 : std::unordered_map<NodeId, std::unordered_map<uint256, CSigSharesInv, StaticSaltedHasher>> sigSharesToAnnounce;
1104 83875 : std::unordered_map<NodeId, std::vector<CSigSesAnn>> sigSessionAnnouncements;
1105 :
1106 83875 : auto addSigSesAnnIfNeeded = [&](NodeId nodeId, const uint256& signHash) {
1107 0 : auto& nodeState = nodeStates[nodeId];
1108 0 : auto session = nodeState.GetSessionBySignHash(signHash);
1109 0 : assert(session);
1110 0 : if (session->sendSessionId == (uint32_t)-1) {
1111 0 : session->sendSessionId = nodeState.nextSendSessionId++;
1112 :
1113 0 : CSigSesAnn sigSesAnn;
1114 0 : sigSesAnn.sessionId = session->sendSessionId;
1115 0 : sigSesAnn.llmqType = (uint8_t)session->llmqType;
1116 0 : sigSesAnn.quorumHash = session->quorumHash;
1117 0 : sigSesAnn.id = session->id;
1118 0 : sigSesAnn.msgHash = session->msgHash;
1119 :
1120 0 : sigSessionAnnouncements[nodeId].emplace_back(sigSesAnn);
1121 : }
1122 0 : return session->sendSessionId;
1123 83875 : };
1124 :
1125 167750 : std::vector<CNode*> vNodesCopy = g_connman->CopyNodeVector(CConnman::FullyConnectedOnly);
1126 :
1127 83875 : {
1128 83875 : LOCK(cs);
1129 83875 : CollectSigSharesToSend(sigSharesToSend, vNodesCopy);
1130 :
1131 83875 : for (auto& p : sigSharesToRequest) {
1132 0 : for (auto& p2 : p.second) {
1133 0 : p2.second.sessionId = addSigSesAnnIfNeeded(p.first, p2.first);
1134 : }
1135 : }
1136 83875 : for (auto& p : sigShareBatchesToSend) {
1137 0 : for (auto& p2 : p.second) {
1138 0 : p2.second.sessionId = addSigSesAnnIfNeeded(p.first, p2.first);
1139 : }
1140 : }
1141 83875 : for (auto& p : sigSharesToAnnounce) {
1142 0 : for (auto& p2 : p.second) {
1143 0 : p2.second.sessionId = addSigSesAnnIfNeeded(p.first, p2.first);
1144 : }
1145 : }
1146 : }
1147 :
1148 83875 : bool didSend = false;
1149 :
1150 486588 : for (auto& pnode : vNodesCopy) {
1151 402713 : CNetMsgMaker msgMaker(pnode->GetSendVersion());
1152 :
1153 402713 : auto it1 = sigSessionAnnouncements.find(pnode->GetId());
1154 402713 : if (it1 != sigSessionAnnouncements.end()) {
1155 0 : std::vector<CSigSesAnn> msgs;
1156 0 : msgs.reserve(it1->second.size());
1157 0 : for (auto& sigSesAnn : it1->second) {
1158 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QSIGSESANN signHash=%s, sessionId=%d, node=%d\n",
1159 : llmq::utils::BuildSignHash(sigSesAnn).ToString(), sigSesAnn.sessionId, pnode->GetId());
1160 0 : msgs.emplace_back(sigSesAnn);
1161 0 : if (msgs.size() == MAX_MSGS_CNT_QSIGSESANN) {
1162 0 : g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSESANN, msgs), false);
1163 0 : msgs.clear();
1164 : didSend = true;
1165 : }
1166 : }
1167 0 : if (!msgs.empty()) {
1168 0 : g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSESANN, msgs), false);
1169 0 : didSend = true;
1170 : }
1171 : }
1172 :
1173 402713 : auto it = sigSharesToRequest.find(pnode->GetId());
1174 402713 : if (it != sigSharesToRequest.end()) {
1175 0 : std::vector<CSigSharesInv> msgs;
1176 0 : for (auto& p : it->second) {
1177 0 : assert(p.second.CountSet() != 0);
1178 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QGETSIGSHARES signHash=%s, inv={%s}, node=%d\n",
1179 : p.first.ToString(), p.second.ToString(), pnode->GetId());
1180 0 : msgs.emplace_back(std::move(p.second));
1181 0 : if (msgs.size() == MAX_MSGS_CNT_QGETSIGSHARES) {
1182 0 : g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QGETSIGSHARES, msgs), false);
1183 0 : msgs.clear();
1184 : didSend = true;
1185 : }
1186 : }
1187 0 : if (!msgs.empty()) {
1188 0 : g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QGETSIGSHARES, msgs), false);
1189 0 : didSend = true;
1190 : }
1191 : }
1192 :
1193 402713 : auto jt = sigShareBatchesToSend.find(pnode->GetId());
1194 402713 : if (jt != sigShareBatchesToSend.end()) {
1195 0 : size_t totalSigsCount = 0;
1196 0 : std::vector<CBatchedSigShares> msgs;
1197 0 : for (auto& p : jt->second) {
1198 0 : assert(!p.second.sigShares.empty());
1199 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QBSIGSHARES signHash=%s, inv={%s}, node=%d\n",
1200 : p.first.ToString(), p.second.ToInvString(), pnode->GetId());
1201 0 : if (totalSigsCount + p.second.sigShares.size() > MAX_MSGS_TOTAL_BATCHED_SIGS) {
1202 0 : g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QBSIGSHARES, msgs), false);
1203 0 : msgs.clear();
1204 : totalSigsCount = 0;
1205 : didSend = true;
1206 : }
1207 0 : totalSigsCount += p.second.sigShares.size();
1208 0 : msgs.emplace_back(std::move(p.second));
1209 : }
1210 0 : if (!msgs.empty()) {
1211 0 : g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QBSIGSHARES, std::move(msgs)), false);
1212 0 : didSend = true;
1213 : }
1214 : }
1215 :
1216 402713 : auto kt = sigSharesToAnnounce.find(pnode->GetId());
1217 402713 : if (kt != sigSharesToAnnounce.end()) {
1218 0 : std::vector<CSigSharesInv> msgs;
1219 0 : for (auto& p : kt->second) {
1220 0 : assert(p.second.CountSet() != 0);
1221 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QSIGSHARESINV signHash=%s, inv={%s}, node=%d\n",
1222 : p.first.ToString(), p.second.ToString(), pnode->GetId());
1223 0 : msgs.emplace_back(std::move(p.second));
1224 0 : if (msgs.size() == MAX_MSGS_CNT_QSIGSHARESINV) {
1225 0 : g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARESINV, msgs), false);
1226 0 : msgs.clear();
1227 : didSend = true;
1228 : }
1229 : }
1230 0 : if (!msgs.empty()) {
1231 0 : g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARESINV, msgs), false);
1232 0 : didSend = true;
1233 : }
1234 : }
1235 :
1236 402713 : auto lt = sigSharesToSend.find(pnode->GetId());
1237 402713 : if (lt != sigSharesToSend.end()) {
1238 1324 : std::vector<CSigShare> msgs;
1239 1534 : for (auto& sigShare : lt->second) {
1240 1744 : LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QSIGSHARE signHash=%s, node=%d\n",
1241 : sigShare.GetSignHash().ToString(), pnode->GetId());
1242 872 : msgs.emplace_back(std::move(sigShare));
1243 872 : if (msgs.size() == MAX_MSGS_SIG_SHARES) {
1244 0 : g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARE, msgs), false);
1245 0 : msgs.clear();
1246 0 : didSend = true;
1247 : }
1248 : }
1249 662 : if (!msgs.empty()) {
1250 662 : g_connman->PushMessage(pnode, msgMaker.Make(NetMsgType::QSIGSHARE, msgs), false);
1251 662 : didSend = true;
1252 : }
1253 : }
1254 : }
1255 :
1256 : // looped through all nodes, release them
1257 83875 : g_connman->ReleaseNodeVector(vNodesCopy);
1258 :
1259 167750 : return didSend;
1260 : }
1261 :
1262 0 : bool CSigSharesManager::GetSessionInfoByRecvId(NodeId nodeId, uint32_t sessionId, CSigSharesNodeState::SessionInfo& retInfo)
1263 : {
1264 0 : LOCK(cs);
1265 0 : return nodeStates[nodeId].GetSessionInfoByRecvId(sessionId, retInfo);
1266 : }
1267 :
1268 0 : CSigShare CSigSharesManager::RebuildSigShare(const CSigSharesNodeState::SessionInfo& session, const CBatchedSigShares& batchedSigShares, size_t idx)
1269 : {
1270 0 : assert(idx < batchedSigShares.sigShares.size());
1271 0 : auto& s = batchedSigShares.sigShares[idx];
1272 0 : CSigShare sigShare;
1273 0 : sigShare.llmqType = session.llmqType;
1274 0 : sigShare.quorumHash = session.quorumHash;
1275 0 : sigShare.quorumMember = s.first;
1276 0 : sigShare.id = session.id;
1277 0 : sigShare.msgHash = session.msgHash;
1278 0 : sigShare.sigShare = s.second;
1279 0 : sigShare.UpdateKey();
1280 0 : return sigShare;
1281 : }
1282 :
1283 155386 : void CSigSharesManager::Cleanup()
1284 : {
1285 155386 : int64_t now = GetAdjustedTime();
1286 155386 : if (now - lastCleanupTime < 5) {
1287 148990 : return;
1288 : }
1289 :
1290 : // This map is first filled with all quorums found in all sig shares. Then we remove all inactive quorums and
1291 : // loop through all sig shares again to find the ones belonging to the inactive quorums. We then delete the
1292 : // sessions belonging to the sig shares. At the same time, we use this map as a cache when we later need to resolve
1293 : // quorumHash -> quorumPtr (as GetQuorum() requires cs_main, leading to deadlocks with cs held)
1294 12792 : std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher> quorums;
1295 :
1296 6396 : {
1297 6396 : LOCK(cs);
1298 6396 : sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
1299 793 : quorums.emplace(std::make_pair((Consensus::LLMQType) sigShare.llmqType, sigShare.quorumHash), nullptr);
1300 793 : });
1301 : }
1302 :
1303 : // Find quorums which became inactive
1304 6396 : for (auto it = quorums.begin(); it != quorums.end(); ) {
1305 228 : if (llmq::utils::IsQuorumActive(it->first.first, it->first.second)) {
1306 216 : it->second = quorumManager->GetQuorum(it->first.first, it->first.second);
1307 6840 : ++it;
1308 : } else {
1309 12 : it = quorums.erase(it);
1310 : }
1311 : }
1312 :
1313 6396 : {
1314 : // Now delete sessions which are for inactive quorums
1315 6396 : LOCK(cs);
1316 12792 : std::unordered_set<uint256, StaticSaltedHasher> inactiveQuorumSessions;
1317 6396 : sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
1318 793 : if (!quorums.count(std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash))) {
1319 60 : inactiveQuorumSessions.emplace(sigShare.GetSignHash());
1320 : }
1321 793 : });
1322 6456 : for (auto& signHash : inactiveQuorumSessions) {
1323 60 : RemoveSigSharesForSession(signHash);
1324 : }
1325 : }
1326 :
1327 6396 : {
1328 6396 : LOCK(cs);
1329 :
1330 : // Remove sessions which were successfully recovered
1331 12792 : std::unordered_set<uint256, StaticSaltedHasher> doneSessions;
1332 6396 : sigShares.ForEach([&](const SigShareKey& k, const CSigShare& sigShare) {
1333 733 : if (doneSessions.count(sigShare.GetSignHash())) {
1334 : return;
1335 : }
1336 733 : if (quorumSigningManager->HasRecoveredSigForSession(sigShare.GetSignHash())) {
1337 0 : doneSessions.emplace(sigShare.GetSignHash());
1338 : }
1339 : });
1340 6396 : for (auto& signHash : doneSessions) {
1341 0 : RemoveSigSharesForSession(signHash);
1342 : }
1343 :
1344 : // Remove sessions which timed out
1345 12792 : std::unordered_set<uint256, StaticSaltedHasher> timeoutSessions;
1346 7129 : for (auto& p : timeSeenForSessions) {
1347 733 : auto& signHash = p.first;
1348 733 : int64_t lastSeenTime = p.second;
1349 :
1350 733 : if (now - lastSeenTime >= SESSION_NEW_SHARES_TIMEOUT) {
1351 733 : timeoutSessions.emplace(signHash);
1352 : }
1353 : }
1354 6396 : for (auto& signHash : timeoutSessions) {
1355 0 : size_t count = sigShares.CountForSignHash(signHash);
1356 :
1357 0 : if (count > 0) {
1358 0 : auto m = sigShares.GetAllForSignHash(signHash);
1359 0 : assert(m);
1360 :
1361 0 : auto& oneSigShare = m->begin()->second;
1362 :
1363 0 : std::string strMissingMembers;
1364 0 : if (LogAcceptCategory(BCLog::LogFlags::LLMQ)) {
1365 0 : auto quorumIt = quorums.find(std::make_pair((Consensus::LLMQType)oneSigShare.llmqType, oneSigShare.quorumHash));
1366 0 : if (quorumIt != quorums.end()) {
1367 0 : auto& quorum = quorumIt->second;
1368 0 : for (size_t i = 0; i < quorum->members.size(); i++) {
1369 0 : if (!m->count((uint16_t)i)) {
1370 0 : auto& dmn = quorum->members[i];
1371 0 : strMissingMembers += strprintf("\n %s", dmn->proTxHash.ToString());
1372 : }
1373 : }
1374 : }
1375 : }
1376 :
1377 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signing session timed out. signHash=%s, id=%s, msgHash=%s, sigShareCount=%d, missingMembers=%s\n", __func__,
1378 : signHash.ToString(), oneSigShare.id.ToString(), oneSigShare.msgHash.ToString(), count, strMissingMembers);
1379 : } else {
1380 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signing session timed out. signHash=%s, sigShareCount=%d\n", __func__,
1381 : signHash.ToString(), count);
1382 : }
1383 0 : RemoveSigSharesForSession(signHash);
1384 : }
1385 : }
1386 :
1387 : // Find node states for peers that disappeared from CConnman
1388 12792 : std::unordered_set<NodeId> nodeStatesToDelete;
1389 6822 : for (auto& p : nodeStates) {
1390 426 : nodeStatesToDelete.emplace(p.first);
1391 : }
1392 6396 : g_connman->ForEachNode([&](CNode* pnode) {
1393 21605 : nodeStatesToDelete.erase(pnode->GetId());
1394 21605 : });
1395 :
1396 : // Now delete these node states
1397 12792 : LOCK(cs);
1398 6398 : for (auto nodeId : nodeStatesToDelete) {
1399 2 : auto& nodeState = nodeStates[nodeId];
1400 : // remove global requested state to force a re-request from another node
1401 2 : nodeState.requestedSigShares.ForEach([&](const SigShareKey& k, bool) {
1402 0 : sigSharesRequested.Erase(k);
1403 : });
1404 2 : nodeStates.erase(nodeId);
1405 : }
1406 :
1407 6396 : lastCleanupTime = GetAdjustedTime();
1408 : }
1409 :
1410 2109 : void CSigSharesManager::RemoveSigSharesForSession(const uint256& signHash)
1411 : {
1412 6720 : for (auto& p : nodeStates) {
1413 4611 : auto& ns = p.second;
1414 4611 : ns.RemoveSession(signHash);
1415 : }
1416 :
1417 2109 : sigSharesRequested.EraseAllForSignHash(signHash);
1418 2109 : sigSharesToAnnounce.EraseAllForSignHash(signHash);
1419 2109 : sigShares.EraseAllForSignHash(signHash);
1420 2109 : signedSessions.erase(signHash);
1421 2109 : timeSeenForSessions.erase(signHash);
1422 2109 : }
1423 :
1424 155386 : void CSigSharesManager::RemoveBannedNodeStates()
1425 : {
1426 : // Called regularly to cleanup local node states for banned nodes
1427 :
1428 310772 : LOCK2(cs, cs_main);
1429 310772 : std::unordered_set<NodeId> toRemove;
1430 155386 : for (auto it = nodeStates.begin(); it != nodeStates.end();) {
1431 24041 : if (IsBanned(it->first)) {
1432 : // re-request sigshares from other nodes
1433 0 : it->second.requestedSigShares.ForEach([&](const SigShareKey& k, int64_t) {
1434 0 : sigSharesRequested.Erase(k);
1435 : });
1436 0 : it = nodeStates.erase(it);
1437 : } else {
1438 203468 : ++it;
1439 : }
1440 : }
1441 155386 : }
1442 :
1443 0 : void CSigSharesManager::BanNode(NodeId nodeId)
1444 : {
1445 0 : if (nodeId == -1) {
1446 0 : return;
1447 : }
1448 :
1449 0 : {
1450 0 : LOCK(cs_main);
1451 0 : Misbehaving(nodeId, 100);
1452 : }
1453 :
1454 0 : LOCK(cs);
1455 0 : auto it = nodeStates.find(nodeId);
1456 0 : if (it == nodeStates.end()) {
1457 0 : return;
1458 : }
1459 0 : auto& nodeState = it->second;
1460 :
1461 : // Whatever we requested from him, let's request it from someone else now
1462 0 : nodeState.requestedSigShares.ForEach([&](const SigShareKey& k, int64_t) {
1463 0 : sigSharesRequested.Erase(k);
1464 : });
1465 0 : nodeState.requestedSigShares.Clear();
1466 :
1467 0 : nodeState.banned = true;
1468 : }
1469 :
1470 347 : void CSigSharesManager::WorkThreadMain()
1471 : {
1472 347 : int64_t lastSendTime = 0;
1473 155386 : while (!interruptSigningShare) {
1474 155386 : bool didWork = false;
1475 :
1476 155386 : RemoveBannedNodeStates();
1477 155386 : didWork |= quorumSigningManager->ProcessPendingRecoveredSigs(*g_connman);
1478 155386 : didWork |= ProcessPendingSigShares(*g_connman);
1479 155386 : didWork |= SignPendingSigShares();
1480 :
1481 155386 : if (GetTimeMillis() - lastSendTime > 100) {
1482 83875 : SendMessages();
1483 83875 : lastSendTime = GetTimeMillis();
1484 : }
1485 :
1486 155386 : Cleanup();
1487 155386 : quorumSigningManager->Cleanup();
1488 :
1489 : // TODO Wakeup when pending signing is needed?
1490 155386 : if (!didWork) {
1491 154029 : if (!interruptSigningShare.sleep_for(std::chrono::milliseconds(100))) {
1492 : return;
1493 : }
1494 : }
1495 : }
1496 : }
1497 :
1498 968 : void CSigSharesManager::AsyncSign(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash)
1499 : {
1500 968 : LOCK(cs);
1501 968 : pendingSigns.emplace_back(quorum, id, msgHash);
1502 968 : }
1503 :
1504 155386 : bool CSigSharesManager::SignPendingSigShares()
1505 : {
1506 310772 : std::vector<std::tuple<const CQuorumCPtr, uint256, uint256>> v;
1507 155386 : {
1508 155386 : LOCK(cs);
1509 155386 : v = std::move(pendingSigns);
1510 : }
1511 :
1512 156354 : for (auto& t : v) {
1513 968 : Sign(std::get<0>(t), std::get<1>(t), std::get<2>(t));
1514 : }
1515 :
1516 155386 : return !v.empty();
1517 : }
1518 :
1519 968 : void CSigSharesManager::Sign(const CQuorumCPtr& quorum, const uint256& id, const uint256& msgHash)
1520 : {
1521 1936 : cxxtimer::Timer t(true);
1522 :
1523 968 : if (!quorum->IsValidMember(activeMasternodeManager->GetProTx())) {
1524 0 : return;
1525 : }
1526 :
1527 1936 : CBLSSecretKey skShare = quorum->GetSkShare();
1528 968 : if (!skShare.IsValid()) {
1529 0 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have our skShare for quorum %s\n", __func__, quorum->qc.quorumHash.ToString());
1530 0 : return;
1531 : }
1532 :
1533 968 : int memberIdx = quorum->GetMemberIndex(activeMasternodeManager->GetProTx());
1534 968 : if (memberIdx == -1) {
1535 : // this should really not happen (IsValidMember gave true)
1536 : return;
1537 : }
1538 :
1539 1936 : CSigShare sigShare;
1540 968 : sigShare.llmqType = quorum->params.type;
1541 968 : sigShare.quorumHash = quorum->qc.quorumHash;
1542 968 : sigShare.id = id;
1543 968 : sigShare.msgHash = msgHash;
1544 968 : sigShare.quorumMember = (uint16_t)memberIdx;
1545 968 : uint256 signHash = llmq::utils::BuildSignHash(sigShare);
1546 :
1547 968 : sigShare.sigShare.Set(skShare.Sign(signHash));
1548 968 : if (!sigShare.sigShare.Get().IsValid()) {
1549 0 : LogPrintf("CSigSharesManager::%s -- failed to sign sigShare. signHahs=%s, id=%s, msgHash=%s, time=%s\n", __func__,
1550 0 : signHash.ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), t.count());
1551 0 : return;
1552 : }
1553 :
1554 968 : sigShare.UpdateKey();
1555 :
1556 4840 : LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signed sigShare. signHash=%s, id=%s, msgHash=%s, llmqType=%d, quorum=%s, time=%s\n", __func__,
1557 : signHash.ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), quorum->params.type, quorum->qc.quorumHash.ToString(), t.count());
1558 968 : ProcessSigShare(-1, sigShare, *g_connman, quorum);
1559 :
1560 1936 : LOCK(cs);
1561 968 : auto& session = signedSessions[sigShare.GetSignHash()];
1562 968 : session.sigShare = sigShare;
1563 968 : session.quorum = quorum;
1564 968 : session.nextAttemptTime = 0;
1565 968 : session.attempt = 0;
1566 : }
1567 :
1568 : // causes all known sigShares to be re-announced
1569 0 : void CSigSharesManager::ForceReAnnouncement(const CQuorumCPtr& quorum, Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash)
1570 : {
1571 0 : LOCK(cs);
1572 0 : auto signHash = llmq::utils::BuildSignHash(llmqType, quorum->qc.quorumHash, id, msgHash);
1573 0 : auto sigs = sigShares.GetAllForSignHash(signHash);
1574 0 : if (sigs) {
1575 0 : for (auto& p : *sigs) {
1576 : // re-announce every sigshare to every node
1577 0 : sigSharesToAnnounce.Add(std::make_pair(signHash, p.first), true);
1578 : }
1579 : }
1580 0 : for (auto& p : nodeStates) {
1581 0 : CSigSharesNodeState& nodeState = p.second;
1582 0 : auto session = nodeState.GetSessionBySignHash(signHash);
1583 0 : if (!session) {
1584 0 : continue;
1585 : }
1586 : // pretend that the other node doesn't know about any shares so that we re-announce everything
1587 0 : session->knows.SetAll(false);
1588 : // we need to use a new session id as we don't know if the other node has run into a timeout already
1589 0 : session->sendSessionId = (uint32_t)-1;
1590 : }
1591 0 : }
1592 :
1593 2049 : void CSigSharesManager::HandleNewRecoveredSig(const llmq::CRecoveredSig& recoveredSig)
1594 : {
1595 2049 : LOCK(cs);
1596 2049 : RemoveSigSharesForSession(llmq::utils::BuildSignHash(recoveredSig));
1597 2049 : }
1598 :
1599 : } // namespace llmq
|