PIVX Core  5.6.99
P2P Digital Currency
quorums_dkgsession.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018-2021 The Dash Core developers
2 // Copyright (c) 2022 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 
7 
8 #include "activemasternode.h"
9 #include "bls/key_io.h"
10 #include "chainparams.h"
11 #include "cxxtimer.h"
12 #include "init.h"
15 #include "llmq/quorums_debug.h"
17 #include "net.h"
19 #include "univalue.h"
20 #include "validation.h"
21 
22 namespace llmq
23 {
24 
25 static RecursiveMutex cs_simDkgError;
26 static std::map<std::string, double> simDkgErrorMap = {
27  {"contribution-omit", 0.0},
28  {"contribution-lie", 0.0},
29  {"complain-lie", 0.0},
30  {"justify-lie", 0.0},
31  {"justify-omit", 0.0},
32  {"commit-omit", 0.0},
33  {"commit-lie", 0.0}
34 };
35 
36 bool SetSimulatedDKGErrorRate(const std::string& error_type, double rate)
37 {
38  LOCK(cs_simDkgError);
39  auto it = simDkgErrorMap.find(error_type);
40  if (it != simDkgErrorMap.end()) {
41  it->second = rate;
42  return true;
43  }
44  return false;
45 }
46 
47 static double GetSimulatedErrorRate(const std::string& error_type)
48 {
49  LOCK(cs_simDkgError);
50  auto it = simDkgErrorMap.find(error_type);
51  if (it != simDkgErrorMap.end()) {
52  return it->second;
53  }
54  return 0;
55 }
56 
57 bool CDKGSession::ShouldSimulateError(const std::string& error_type)
58 {
60  // error simulation available only for LLMQ_TEST
61  return false;
62  }
63  double rate = GetSimulatedErrorRate(error_type);
64  return GetRandBool(rate);
65 }
66 
67 CDKGLogger::CDKGLogger(const CDKGSession& _quorumDkg, const std::string& _func) :
68  CDKGLogger(_quorumDkg.params.name, _quorumDkg.pindexQuorum->GetBlockHash(), _quorumDkg.pindexQuorum->nHeight, _quorumDkg.AreWeMember(), _func)
69 {
70 }
71 
72 CDKGLogger::CDKGLogger(const std::string& _llmqTypeName, const uint256& _quorumHash, int _height, bool _areWeMember, const std::string& _func) :
73  CBatchedLogger(g_logger, BCLog::DKG, strprintf("QuorumDKG(type=%s, height=%d, member=%d, func=%s)", _llmqTypeName, _height, _areWeMember, _func))
74 {
75 }
76 
77 
79  badMembers((size_t)params.size), complainForMembers((size_t)params.size)
80 {
81 }
82 
84  validMembers((size_t)params.size)
85 {
86 }
87 
89  dmn(_dmn),
90  idx(_idx),
91  id(_dmn->proTxHash)
92 {
93 
94 }
95 
96 bool CDKGSession::Init(const CBlockIndex* _pindexQuorum, const std::vector<CDeterministicMNCPtr>& mns, const uint256& _myProTxHash)
97 {
98  if (mns.size() < (size_t)params.minSize) {
99  // don't use CDKGLogger until CDKGSession is fully initialized
100  LogPrint(BCLog::DKG, "CDKGSession::%s: not enough members (%d < %d), aborting init\n", __func__, mns.size(), params.minSize);
101  return false;
102  }
103 
104  pindexQuorum = _pindexQuorum;
105 
106  members.resize(mns.size());
107  memberIds.resize(members.size());
108  receivedVvecs.resize(members.size());
109  receivedSkContributions.resize(members.size());
110 
111  for (size_t i = 0; i < mns.size(); i++) {
112  members[i] = std::unique_ptr<CDKGMember>(new CDKGMember(mns[i], i));
113  membersMap.emplace(members[i]->dmn->proTxHash, i);
114  memberIds[i] = members[i]->id;
115  }
116 
117  if (!_myProTxHash.IsNull()) {
118  for (size_t i = 0; i < members.size(); i++) {
119  auto& m = members[i];
120  if (m->dmn->proTxHash == _myProTxHash) {
121  myIdx = i;
122  myProTxHash = _myProTxHash;
123  myId = m->id;
124  break;
125  }
126  }
127  }
128 
129  if (myProTxHash.IsNull()) {
130  LogPrint(BCLog::DKG, "CDKGSession::%s: initialized as observer. mns=%d\n", __func__, mns.size());
131  } else {
134  LogPrint(BCLog::DKG, "CDKGSession::%s: initialized as member. mns=%d\n", __func__, mns.size());
135  }
136 
137  return true;
138 }
139 
141 {
142  CDKGLogger logger(*this, __func__);
143 
144  if (!AreWeMember()) {
145  return;
146  }
147 
148  cxxtimer::Timer t1(true);
149  logger.Batch("generating contributions");
151  // this should never happen actually
152  logger.Batch("GenerateContributions failed");
153  return;
154  }
155  logger.Batch("generated contributions. time=%d", t1.count());
156 
157  SendContributions(pendingMessages);
158 }
159 
161 {
162  CDKGLogger logger(*this, __func__);
163 
164  assert(AreWeMember());
165 
166  logger.Batch("sending contributions");
167 
168  if (ShouldSimulateError("contribution-omit")) {
169  logger.Batch("omitting");
170  return;
171  }
172 
173  CDKGContribution qc;
174  qc.llmqType = (uint8_t)params.type;
176  qc.proTxHash = myProTxHash;
177  qc.vvec = vvecContribution;
178 
179  cxxtimer::Timer t1(true);
180  qc.contributions = std::make_shared<CBLSIESMultiRecipientObjects<CBLSSecretKey>>();
181  qc.contributions->InitEncrypt(members.size());
182 
183  for (size_t i = 0; i < members.size(); i++) {
184  auto& m = members[i];
185  CBLSSecretKey skContrib = skContributions[i];
186 
187  if (i != myIdx && ShouldSimulateError("contribution-lie")) {
188  logger.Batch("lying for %s", m->dmn->proTxHash.ToString());
189  skContrib.MakeNewKey();
190  }
191 
192  if (!qc.contributions->Encrypt(i, m->dmn->pdmnState->pubKeyOperator.Get(), skContrib, PROTOCOL_VERSION)) {
193  logger.Batch("failed to encrypt contribution for %s", m->dmn->proTxHash.ToString());
194  return;
195  }
196  }
197 
198  logger.Batch("encrypted contributions. time=%d", t1.count());
199 
201 
202  logger.Flush();
203 
204  quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
205  status.sentContributions = true;
206  return true;
207  });
208 
209  pendingMessages.PushPendingMessage(-1, qc, MSG_QUORUM_CONTRIB);
210 }
211 
212 // only performs cheap verifications, but not the signature of the message. this is checked with batched verification
213 bool CDKGSession::PreVerifyMessage(const CDKGContribution& qc, bool& retBan) const
214 {
215  CDKGLogger logger(*this, __func__);
216 
217  retBan = false;
218 
219  if (qc.quorumHash != pindexQuorum->GetBlockHash()) {
220  logger.Batch("contribution for wrong quorum, rejecting");
221  return false;
222  }
223 
224  auto member = GetMember(qc.proTxHash);
225  if (!member) {
226  logger.Batch("contributor not a member of this quorum, rejecting contribution");
227  retBan = true;
228  return false;
229  }
230 
231  if (qc.contributions->blobs.size() != members.size()) {
232  logger.Batch("invalid contributions count");
233  retBan = true;
234  return false;
235  }
236  if (qc.vvec->size() != (size_t)params.threshold) {
237  logger.Batch("invalid verification vector length");
238  retBan = true;
239  return false;
240  }
241 
243  logger.Batch("invalid verification vector");
244  retBan = true;
245  return false;
246  }
247 
248  if (member->contributions.size() >= 2) {
249  // don't do any further processing if we got more than 1 valid contributions already
250  // this is a DoS protection against members sending multiple contributions with valid signatures to us
251  // we must bail out before any expensive BLS verification happens
252  logger.Batch("dropping contribution from %s as we already got %d contributions", member->dmn->proTxHash.ToString(), member->contributions.size());
253  return false;
254  }
255 
256  return true;
257 }
258 
259 void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGContribution& qc, bool& retBan)
260 {
261  CDKGLogger logger(*this, __func__);
262 
263  retBan = false;
264 
265  auto member = GetMember(qc.proTxHash);
266 
267  cxxtimer::Timer t1(true);
268  logger.Batch("received contribution from %s", qc.proTxHash.ToString());
269 
270  {
271  // relay, no matter if further verification fails
272  // This ensures the whole quorum sees the bad behavior
273  LOCK(invCs);
274 
275  if (member->contributions.size() >= 2) {
276  // only relay up to 2 contributions, that's enough to let the other members know about his bad behavior
277  return;
278  }
279 
280  contributions.emplace(hash, qc);
281  member->contributions.emplace(hash);
282 
283  CInv inv(MSG_QUORUM_CONTRIB, hash);
285 
286  quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
287  status.receivedContribution = true;
288  return true;
289  });
290 
291  if (member->contributions.size() > 1) {
292  // don't do any further processing if we got more than 1 contribution. we already relayed it,
293  // so others know about his bad behavior
294  MarkBadMember(member);
295  logger.Batch("%s did send multiple contributions", member->dmn->proTxHash.ToString());
296  return;
297  }
298  }
299 
300  receivedVvecs[member->idx] = qc.vvec;
301 
302  int receivedCount = 0;
303  for (const auto& m : members) {
304  if (!m->contributions.empty()) {
305  receivedCount++;
306  }
307  }
308 
309  logger.Batch("received and relayed contribution. received=%d/%d, time=%d", receivedCount, members.size(), t1.count());
310 
311  cxxtimer::Timer t2(true);
312 
313  if (!AreWeMember()) {
314  // can't further validate
315  return;
316  }
317 
319 
320  bool complain = false;
321  CBLSSecretKey skContribution;
322  if (!qc.contributions->Decrypt(myIdx, *activeMasternodeManager->OperatorKey(), skContribution, PROTOCOL_VERSION)) {
323  logger.Batch("contribution from %s could not be decrypted", member->dmn->proTxHash.ToString());
324  complain = true;
325  } else if (member->idx != myIdx && ShouldSimulateError("complain-lie")) {
326  logger.Batch("lying/complaining for %s", member->dmn->proTxHash.ToString());
327  complain = true;
328  }
329 
330  if (complain) {
331  member->weComplain = true;
332  quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
333  status.weComplain = true;
334  return true;
335  });
336  return;
337  }
338 
339  logger.Batch("decrypted our contribution share. time=%d", t2.count());
340 
341  bool verifyPending = false;
342  receivedSkContributions[member->idx] = skContribution;
343  pendingContributionVerifications.emplace_back(member->idx);
344  if (pendingContributionVerifications.size() >= 32) {
345  verifyPending = true;
346  }
347 
348  if (verifyPending) {
350  }
351 }
352 
353 // Verifies all pending secret key contributions in one batch
354 // This is done by aggregating the verification vectors belonging to the secret key contributions
355 // The resulting aggregated vvec is then used to recover a public key share
356 // The public key share must match the public key belonging to the aggregated secret key contributions
357 // See CBLSWorker::VerifyContributionShares for more details.
359 {
360  CDKGLogger logger(*this, __func__);
361 
362  cxxtimer::Timer t1(true);
363 
364  std::vector<size_t> pend = std::move(pendingContributionVerifications);
365  if (pend.empty()) {
366  return;
367  }
368 
369  std::vector<size_t> memberIndexes;
370  std::vector<BLSVerificationVectorPtr> vvecs;
372 
373  for (const auto& idx : pend) {
374  auto& m = members[idx];
375  if (m->bad || m->weComplain) {
376  continue;
377  }
378  memberIndexes.emplace_back(idx);
379  vvecs.emplace_back(receivedVvecs[idx]);
380  skContributions.emplace_back(receivedSkContributions[idx]);
381  }
382 
384  if (result.size() != memberIndexes.size()) {
385  logger.Batch("VerifyContributionShares returned result of size %d but size %d was expected, something is wrong", result.size(), memberIndexes.size());
386  return;
387  }
388 
389  for (size_t i = 0; i < memberIndexes.size(); i++) {
390  if (!result[i]) {
391  auto& m = members[memberIndexes[i]];
392  logger.Batch("invalid contribution from %s. will complain later", m->dmn->proTxHash.ToString());
393  m->weComplain = true;
394  quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, m->idx, [&](CDKGDebugMemberStatus& status) {
395  status.weComplain = true;
396  return true;
397  });
398  } else {
399  size_t memberIdx = memberIndexes[i];
401  }
402  }
403 
404  logger.Batch("verified %d pending contributions. time=%d", pend.size(), t1.count());
405 }
406 
408 {
409  if (!AreWeMember()) {
410  return;
411  }
412 
414 
415  CDKGLogger logger(*this, __func__);
416 
417  // we check all members if they sent us their contributions
418  // we consider members as bad if they missed to send anything or if they sent multiple
419  // in both cases we won't give him a second chance as he is either down, buggy or an adversary
420  // we assume that such a participant will be marked as bad by the whole network in most cases,
421  // as propagation will ensure that all nodes see the same vvecs/contributions. In case nodes come to
422  // different conclusions, the aggregation phase will handle this (most voted quorum key wins)
423 
424  cxxtimer::Timer t1(true);
425 
426  for (const auto& m : members) {
427  if (m->bad) {
428  continue;
429  }
430  if (m->contributions.empty()) {
431  logger.Batch("%s did not send any contribution", m->dmn->proTxHash.ToString());
432  MarkBadMember(m.get());
433  continue;
434  }
435  }
436 
437  logger.Batch("verified contributions. time=%d", t1.count());
438  logger.Flush();
439 
441 
442  SendComplaint(pendingMessages);
443 }
444 
446 {
447  CDKGLogger logger(*this, __func__);
448 
449  std::unordered_map<uint256, int, StaticSaltedHasher> protoMap;
450  g_connman->ForEachNode([&](const CNode* pnode) {
451  if (pnode->verifiedProRegTxHash.IsNull()) {
452  return;
453  }
454  protoMap.emplace(pnode->verifiedProRegTxHash, pnode->nVersion);
455  });
456 
457  for (auto& m : members) {
458  if (m->dmn->proTxHash == myProTxHash) {
459  continue;
460  }
461 
462  auto it = protoMap.find(m->dmn->proTxHash);
463  if (it == protoMap.end()) {
464  m->bad = true;
465  logger.Batch("%s is not connected to us", m->dmn->proTxHash.ToString());
466  } else if (it != protoMap.end() && it->second < MNAUTH_NODE_VER_VERSION) {
467  m->bad = true;
468  logger.Batch("%s does not have min proto version %d (has %d)", m->dmn->proTxHash.ToString(), MNAUTH_NODE_VER_VERSION, it->second);
469  }
470 
471  auto lastOutbound = g_mmetaman.GetMetaInfo(m->dmn->proTxHash)->GetLastOutboundSuccess();
472  if (GetAdjustedTime() - lastOutbound > 60 * 60) {
473  m->bad = true;
474  logger.Batch("%s no outbound connection since %d seconds", m->dmn->proTxHash.ToString(), GetAdjustedTime() - lastOutbound);
475  }
476  }
477 }
478 
480 {
481  CDKGLogger logger(*this, __func__);
482 
483  assert(AreWeMember());
484 
485  CDKGComplaint qc(params);
486  qc.llmqType = (uint8_t)params.type;
488  qc.proTxHash = myProTxHash;
489 
490  int badCount = 0;
491  int complaintCount = 0;
492  for (size_t i = 0; i < members.size(); i++) {
493  auto& m = members[i];
494  if (m->bad) {
495  qc.badMembers[i] = true;
496  badCount++;
497  } else if (m->weComplain) {
498  qc.complainForMembers[i] = true;
499  complaintCount++;
500  }
501  }
502 
503  if (badCount == 0 && complaintCount == 0) {
504  return;
505  }
506 
507  logger.Batch("sending complaint. badCount=%d, complaintCount=%d", badCount, complaintCount);
508 
510 
511  logger.Flush();
512 
513  quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
514  status.sentComplaint = true;
515  return true;
516  });
517 
518  pendingMessages.PushPendingMessage(-1, qc, MSG_QUORUM_COMPLAINT);
519 }
520 
521 // only performs cheap verifications, but not the signature of the message. this is checked with batched verification
522 bool CDKGSession::PreVerifyMessage(const CDKGComplaint& qc, bool& retBan) const
523 {
524  CDKGLogger logger(*this, __func__);
525 
526  retBan = false;
527 
528  if (qc.quorumHash != pindexQuorum->GetBlockHash()) {
529  logger.Batch("complaint for wrong quorum, rejecting");
530  return false;
531  }
532 
533  auto member = GetMember(qc.proTxHash);
534  if (!member) {
535  logger.Batch("complainer not a member of this quorum, rejecting complaint");
536  retBan = true;
537  return false;
538  }
539 
540  if (qc.badMembers.size() != (size_t)params.size) {
541  logger.Batch("invalid badMembers bitset size");
542  retBan = true;
543  return false;
544  }
545 
546  if (qc.complainForMembers.size() != (size_t)params.size) {
547  logger.Batch("invalid complainForMembers bitset size");
548  retBan = true;
549  return false;
550  }
551 
552  if (member->complaints.size() >= 2) {
553  // don't do any further processing if we got more than 1 valid complaints already
554  // this is a DoS protection against members sending multiple complaints with valid signatures to us
555  // we must bail out before any expensive BLS verification happens
556  logger.Batch("dropping complaint from %s as we already got %d complaints",
557  member->dmn->proTxHash.ToString(), member->complaints.size());
558  return false;
559  }
560 
561  return true;
562 }
563 
564 void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGComplaint& qc, bool& retBan)
565 {
566  CDKGLogger logger(*this, __func__);
567 
568  retBan = false;
569 
570  logger.Batch("received complaint from %s", qc.proTxHash.ToString());
571 
572  auto member = GetMember(qc.proTxHash);
573 
574  {
575  LOCK(invCs);
576 
577  if (member->complaints.size() >= 2) {
578  // only relay up to 2 complaints, that's enough to let the other members know about his bad behavior
579  return;
580  }
581 
582  complaints.emplace(hash, qc);
583  member->complaints.emplace(hash);
584 
585  CInv inv(MSG_QUORUM_COMPLAINT, hash);
587 
588  quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
589  status.receivedComplaint = true;
590  return true;
591  });
592 
593  if (member->complaints.size() > 1) {
594  // don't do any further processing if we got more than 1 complaint. we already relayed it,
595  // so others know about his bad behavior
596  MarkBadMember(member);
597  logger.Batch("%s did send multiple complaints", member->dmn->proTxHash.ToString());
598  return;
599  }
600  }
601 
602  int receivedCount = 0;
603  for (size_t i = 0; i < members.size(); i++) {
604  auto& m = members[i];
605  if (qc.badMembers[i]) {
606  logger.Batch("%s voted for %s to be bad", member->dmn->proTxHash.ToString(), m->dmn->proTxHash.ToString());
607  m->badMemberVotes.emplace(qc.proTxHash);
608  if (AreWeMember() && i == myIdx) {
609  logger.Batch("%s voted for us to be bad", member->dmn->proTxHash.ToString());
610  }
611  }
612  if (qc.complainForMembers[i]) {
613  m->complaintsFromOthers.emplace(qc.proTxHash);
614  m->someoneComplain = true;
615  quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, m->idx, [&](CDKGDebugMemberStatus& status) {
616  return status.complaintsFromMembers.emplace(member->idx).second;
617  });
618  if (AreWeMember() && i == myIdx) {
619  logger.Batch("%s complained about us", member->dmn->proTxHash.ToString());
620  }
621  }
622  if (!m->complaints.empty()) {
623  receivedCount++;
624  }
625  }
626 
627  logger.Batch("received and relayed complaint. received=%d", receivedCount);
628 }
629 
631 {
632  if (!AreWeMember()) {
633  return;
634  }
635 
636  CDKGLogger logger(*this, __func__);
637 
638  std::set<uint256> justifyFor;
639 
640  for (const auto& m : members) {
641  if (m->bad) {
642  continue;
643  }
644  if (m->badMemberVotes.size() >= (size_t)params.dkgBadVotesThreshold) {
645  logger.Batch("%s marked as bad as %d other members voted for this", m->dmn->proTxHash.ToString(), m->badMemberVotes.size());
646  MarkBadMember(m.get());
647  continue;
648  }
649  if (m->complaints.empty()) {
650  continue;
651  }
652  if (m->complaints.size() != 1) {
653  logger.Batch("%s sent multiple complaints", m->dmn->proTxHash.ToString());
654  MarkBadMember(m.get());
655  continue;
656  }
657 
658  auto& qc = complaints.at(*m->complaints.begin());
659  if (qc.complainForMembers[myIdx]) {
660  justifyFor.emplace(qc.proTxHash);
661  }
662  }
663 
664  logger.Flush();
665  if (!justifyFor.empty()) {
666  SendJustification(pendingMessages, justifyFor);
667  }
668 }
669 
670 void CDKGSession::SendJustification(CDKGPendingMessages& pendingMessages, const std::set<uint256>& forMembers)
671 {
672  CDKGLogger logger(*this, __func__);
673 
674  assert(AreWeMember());
675 
676  logger.Batch("sending justification for %d members", forMembers.size());
677 
679  qj.llmqType = (uint8_t)params.type;
681  qj.proTxHash = myProTxHash;
682  qj.contributions.reserve(forMembers.size());
683 
684  for (size_t i = 0; i < members.size(); i++) {
685  auto& m = members[i];
686  if (!forMembers.count(m->dmn->proTxHash)) {
687  continue;
688  }
689  logger.Batch("justifying for %s", m->dmn->proTxHash.ToString());
690 
691  CBLSSecretKey skContribution = skContributions[i];
692 
693  if (i != myIdx && ShouldSimulateError("justify-lie")) {
694  logger.Batch("lying for %s", m->dmn->proTxHash.ToString());
695  skContribution.MakeNewKey();
696  }
697 
698  qj.contributions.emplace_back(i, skContribution);
699  }
700 
701  if (ShouldSimulateError("justify-omit")) {
702  logger.Batch("omitting");
703  return;
704  }
705 
707 
708  logger.Flush();
709 
710  quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
711  status.sentJustification = true;
712  return true;
713  });
714 
715  pendingMessages.PushPendingMessage(-1, qj, MSG_QUORUM_JUSTIFICATION);
716 }
717 
718 // only performs cheap verifications, but not the signature of the message. this is checked with batched verification
719 bool CDKGSession::PreVerifyMessage(const CDKGJustification& qj, bool& retBan) const
720 {
721  CDKGLogger logger(*this, __func__);
722 
723  retBan = false;
724 
725  if (qj.quorumHash != pindexQuorum->GetBlockHash()) {
726  logger.Batch("justification for wrong quorum, rejecting");
727  return false;
728  }
729 
730  auto member = GetMember(qj.proTxHash);
731  if (!member) {
732  logger.Batch("justifier not a member of this quorum, rejecting justification");
733  retBan = true;
734  return false;
735  }
736 
737  if (qj.contributions.empty()) {
738  logger.Batch("justification with no contributions");
739  retBan = true;
740  return false;
741  }
742 
743  std::set<size_t> contributionsSet;
744  for (const auto& p : qj.contributions) {
745  if (p.first > members.size()) {
746  logger.Batch("invalid contribution index");
747  retBan = true;
748  return false;
749  }
750 
751  if (!contributionsSet.emplace(p.first).second) {
752  logger.Batch("duplicate contribution index");
753  retBan = true;
754  return false;
755  }
756 
757  auto& skShare = p.second;
758  if (!skShare.IsValid()) {
759  logger.Batch("invalid contribution");
760  retBan = true;
761  return false;
762  }
763  }
764 
765  if (member->justifications.size() >= 2) {
766  // don't do any further processing if we got more than 1 valid justification already
767  // this is a DoS protection against members sending multiple justifications with valid signatures to us
768  // we must bail out before any expensive BLS verification happens
769  logger.Batch("dropping justification from %s as we already got %d justifications",
770  member->dmn->proTxHash.ToString(), member->justifications.size());
771  return false;
772  }
773 
774  return true;
775 }
776 
777 void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGJustification& qj, bool& retBan)
778 {
779  CDKGLogger logger(*this, __func__);
780 
781  retBan = false;
782 
783  logger.Batch("received justification from %s", qj.proTxHash.ToString());
784 
785  auto member = GetMember(qj.proTxHash);
786 
787  {
788  LOCK(invCs);
789 
790  if (member->justifications.size() >= 2) {
791  // only relay up to 2 justifications, that's enough to let the other members know about his bad behavior
792  return;
793  }
794 
795  justifications.emplace(hash, qj);
796  member->justifications.emplace(hash);
797 
798  // we always relay, even if further verification fails
799  CInv inv(MSG_QUORUM_JUSTIFICATION, hash);
801 
802  quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
803  status.receivedJustification = true;
804  return true;
805  });
806 
807  if (member->justifications.size() > 1) {
808  // don't do any further processing if we got more than 1 justification. we already relayed it,
809  // so others know about his bad behavior
810  logger.Batch("%s did send multiple justifications", member->dmn->proTxHash.ToString());
811  MarkBadMember(member);
812  return;
813  }
814 
815  if (member->bad) {
816  // we locally determined him to be bad (sent none or more then one contributions)
817  // don't give him a second chance (but we relay the justification in case other members disagree)
818  return;
819  }
820  }
821 
822  for (const auto& p : qj.contributions) {
823  auto& member2 = members[p.first];
824 
825  if (!member->complaintsFromOthers.count(member2->dmn->proTxHash)) {
826  logger.Batch("got justification from %s for %s even though he didn't complain",
827  member->dmn->proTxHash.ToString(), member2->dmn->proTxHash.ToString());
828  MarkBadMember(member);
829  }
830  }
831  if (member->bad) {
832  return;
833  }
834 
835  cxxtimer::Timer t1(true);
836 
837  std::list<std::future<bool>> futures;
838  for (const auto& p : qj.contributions) {
839  auto& member2 = members[p.first];
840  auto& skContribution = p.second;
841 
842  // watch out to not bail out before these async calls finish (they rely on valid references)
843  futures.emplace_back(blsWorker.AsyncVerifyContributionShare(member2->id, receivedVvecs[member->idx], skContribution));
844  }
845  auto resultIt = futures.begin();
846  for (const auto& p : qj.contributions) {
847  auto& member2 = members[p.first];
848  auto& skContribution = p.second;
849 
850  bool result = (resultIt++)->get();
851  if (!result) {
852  logger.Batch(" %s did send an invalid justification for %s", member->dmn->proTxHash.ToString(), member2->dmn->proTxHash.ToString());
853  MarkBadMember(member);
854  } else {
855  logger.Batch(" %s justified for %s", member->dmn->proTxHash.ToString(), member2->dmn->proTxHash.ToString());
856  if (AreWeMember() && member2->id == myId) {
857  receivedSkContributions[member->idx] = skContribution;
858  member->weComplain = false;
859 
860  dkgManager.WriteVerifiedSkContribution(params.type, pindexQuorum, member->dmn->proTxHash, skContribution);
861  }
862  member->complaintsFromOthers.erase(member2->dmn->proTxHash);
863  }
864  }
865 
866  int receivedCount = 0;
867  int expectedCount = 0;
868 
869  for (const auto& m : members) {
870  if (!m->justifications.empty()) {
871  receivedCount++;
872  }
873 
874  if (m->someoneComplain) {
875  expectedCount++;
876  }
877  }
878 
879  logger.Batch("verified justification: received=%d/%d time=%d", receivedCount, expectedCount, t1.count());
880 }
881 
883 {
884  if (!AreWeMember()) {
885  return;
886  }
887 
888  CDKGLogger logger(*this, __func__);
889 
890  std::vector<size_t> badMembers;
891  std::vector<size_t> openComplaintMembers;
892 
893  for (const auto& m : members) {
894  if (m->bad) {
895  badMembers.emplace_back(m->idx);
896  continue;
897  }
898  if (!m->complaintsFromOthers.empty()) {
899  MarkBadMember(m.get());
900  openComplaintMembers.emplace_back(m->idx);
901  }
902  }
903 
904  if (!badMembers.empty() || !openComplaintMembers.empty()) {
905  logger.Batch("verification result:");
906  }
907  if (!badMembers.empty()) {
908  logger.Batch(" members previously determined as bad:");
909  for (const auto& idx : badMembers) {
910  logger.Batch(" %s", members[idx]->dmn->proTxHash.ToString());
911  }
912  }
913  if (!openComplaintMembers.empty()) {
914  logger.Batch(" members with open complaints and now marked as bad:");
915  for (const auto& idx : openComplaintMembers) {
916  logger.Batch(" %s", members[idx]->dmn->proTxHash.ToString());
917  }
918  }
919 
920  logger.Flush();
921 
922  SendCommitment(pendingMessages);
923 }
924 
926 {
927  CDKGLogger logger(*this, __func__);
928 
929  assert(AreWeMember());
930 
931  logger.Batch("sending commitment");
932 
934  qc.llmqType = (uint8_t)params.type;
936  qc.proTxHash = myProTxHash;
937 
938  for (size_t i = 0; i < members.size(); i++) {
939  auto& m = members[i];
940  if (!m->bad) {
941  qc.validMembers[i] = true;
942  }
943  }
944 
945  if (qc.CountValidMembers() < params.minSize) {
946  logger.Batch("not enough valid members. not sending commitment");
947  return;
948  }
949 
950  if (ShouldSimulateError("commit-omit")) {
951  logger.Batch("omitting");
952  return;
953  }
954 
955  cxxtimer::Timer timerTotal(true);
956 
957  cxxtimer::Timer t1(true);
958  std::vector<uint16_t> memberIndexes;
959  std::vector<BLSVerificationVectorPtr> vvecs;
962  logger.Batch("failed to get valid contributions");
963  return;
964  }
965 
967  if (vvec == nullptr) {
968  logger.Batch("failed to build quorum verification vector");
969  return;
970  }
971  t1.stop();
972 
973  cxxtimer::Timer t2(true);
975  if (!skShare.IsValid()) {
976  logger.Batch("failed to build own secret share");
977  return;
978  }
979  t2.stop();
980 
981  logger.Batch("pubKeyShare=%s", bls::EncodePublic(Params(), skShare.GetPublicKey()));
982 
983  cxxtimer::Timer t3(true);
984  qc.quorumPublicKey = (*vvec)[0];
985  qc.quorumVvecHash = ::SerializeHash(*vvec);
986 
987  int lieType = -1;
988  if (ShouldSimulateError("commit-lie")) {
989  lieType = GetRandInt(5);
990  logger.Batch("lying on commitment. lieType=%d", lieType);
991  }
992 
993  if (lieType == 0) {
994  CBLSSecretKey k;
995  k.MakeNewKey();
996  qc.quorumPublicKey = k.GetPublicKey();
997  } else if (lieType == 1) {
998  (*qc.quorumVvecHash.begin())++;
999  }
1000 
1002 
1003  if (lieType == 2) {
1004  (*commitmentHash.begin())++;
1005  }
1006 
1007  qc.sig = activeMasternodeManager->OperatorKey()->Sign(commitmentHash);
1008  qc.quorumSig = skShare.Sign(commitmentHash);
1009 
1010  if (lieType == 3) {
1011  std::vector<uint8_t> buf = qc.sig.ToByteVector();
1012  buf[5]++;
1013  qc.sig.SetByteVector(buf);
1014  } else if (lieType == 4) {
1015  std::vector<uint8_t> buf = qc.quorumSig.ToByteVector();
1016  buf[5]++;
1017  qc.quorumSig.SetByteVector(buf);
1018  }
1019 
1020  t3.stop();
1021  timerTotal.stop();
1022 
1023  logger.Batch("built premature commitment. time1=%d, time2=%d, time3=%d, totalTime=%d",
1024  t1.count(), t2.count(), t3.count(), timerTotal.count());
1025 
1026  logger.Flush();
1027 
1028  quorumDKGDebugManager->UpdateLocalSessionStatus(params.type, [&](CDKGDebugSessionStatus& status) {
1029  status.sentPrematureCommitment = true;
1030  return true;
1031  });
1032 
1033  pendingMessages.PushPendingMessage(-1, qc, MSG_QUORUM_PREMATURE_COMMITMENT);
1034 }
1035 
1036 // only performs cheap verifications, but not the signature of the message. this is checked with batched verification
1037 bool CDKGSession::PreVerifyMessage(const CDKGPrematureCommitment& qc, bool& retBan) const
1038 {
1039  CDKGLogger logger(*this, __func__);
1040 
1041  retBan = false;
1042 
1043  if (qc.quorumHash != pindexQuorum->GetBlockHash()) {
1044  logger.Batch("commitment for wrong quorum, rejecting");
1045  return false;
1046  }
1047 
1048  auto member = GetMember(qc.proTxHash);
1049  if (!member) {
1050  logger.Batch("committer not a member of this quorum, rejecting premature commitment");
1051  retBan = true;
1052  return false;
1053  }
1054 
1055  if (qc.validMembers.size() != (size_t)params.size) {
1056  logger.Batch("invalid validMembers bitset size");
1057  retBan = true;
1058  return false;
1059  }
1060 
1061  if (qc.CountValidMembers() < params.minSize) {
1062  logger.Batch("invalid validMembers count. validMembersCount=%d", qc.CountValidMembers());
1063  retBan = true;
1064  return false;
1065  }
1066  if (!qc.sig.IsValid()) {
1067  logger.Batch("invalid membersSig");
1068  retBan = true;
1069  return false;
1070  }
1071  if (!qc.quorumSig.IsValid()) {
1072  logger.Batch("invalid quorumSig");
1073  retBan = true;
1074  return false;
1075  }
1076 
1077  for (size_t i = members.size(); i < (size_t)params.size; i++) {
1078  if (qc.validMembers[i]) {
1079  retBan = true;
1080  logger.Batch("invalid validMembers bitset. bit %d should not be set", i);
1081  return false;
1082  }
1083  }
1084 
1085  if (member->prematureCommitments.size() >= 2) {
1086  // don't do any further processing if we got more than 1 valid commitment already
1087  // this is a DoS protection against members sending multiple commitments with valid signatures to us
1088  // we must bail out before any expensive BLS verification happens
1089  logger.Batch("dropping commitment from %s as we already got %d commitments",
1090  member->dmn->proTxHash.ToString(), member->prematureCommitments.size());
1091  return false;
1092  }
1093 
1094  return true;
1095 }
1096 
1097 void CDKGSession::ReceiveMessage(const uint256& hash, const CDKGPrematureCommitment& qc, bool& retBan)
1098 {
1099  CDKGLogger logger(*this, __func__);
1100 
1101  retBan = false;
1102 
1103  cxxtimer::Timer t1(true);
1104 
1105  logger.Batch("received premature commitment from %s. validMembers=%d", qc.proTxHash.ToString(), qc.CountValidMembers());
1106 
1107  auto member = GetMember(qc.proTxHash);
1108 
1109  {
1110  LOCK(invCs);
1111 
1112  // keep track of ALL commitments but only relay valid ones (or if we couldn't build the vvec)
1113  // relaying is done further down
1114  prematureCommitments.emplace(hash, qc);
1115  member->prematureCommitments.emplace(hash);
1116  }
1117 
1118  std::vector<uint16_t> memberIndexes;
1119  std::vector<BLSVerificationVectorPtr> vvecs;
1121  BLSVerificationVectorPtr quorumVvec;
1123  quorumVvec = cache.BuildQuorumVerificationVector(::SerializeHash(memberIndexes), vvecs);
1124  }
1125 
1126  if (quorumVvec == nullptr) {
1127  logger.Batch("failed to build quorum verification vector. skipping full verification");
1128  // we might be the unlucky one who didn't receive all contributions, but we still have to relay
1129  // the premature commitment as others might be luckier
1130  } else {
1131  // we got all information that is needed to verify everything (even though we might not be a member of the quorum)
1132  // if any of this verification fails, we won't relay this message. This ensures that invalid messages are lost
1133  // in the network. Nodes relaying such invalid messages to us are not punished as they might have not known
1134  // all contributions. We only handle up to 2 commitments per member, so a DoS shouldn't be possible
1135 
1136  if ((*quorumVvec)[0] != qc.quorumPublicKey) {
1137  logger.Batch("calculated quorum public key does not match");
1138  return;
1139  }
1140  uint256 vvecHash = ::SerializeHash(*quorumVvec);
1141  if (qc.quorumVvecHash != vvecHash) {
1142  logger.Batch("calculated quorum vvec hash does not match");
1143  return;
1144  }
1145 
1146  CBLSPublicKey pubKeyShare = cache.BuildPubKeyShare(::SerializeHash(std::make_pair(memberIndexes, member->id)), quorumVvec, member->id);
1147  if (!pubKeyShare.IsValid()) {
1148  logger.Batch("failed to calculate public key share");
1149  return;
1150  }
1151 
1152  if (!qc.quorumSig.VerifyInsecure(pubKeyShare, qc.GetSignHash())) {
1153  logger.Batch("failed to verify quorumSig");
1154  return;
1155  }
1156  }
1157 
1158  LOCK(invCs);
1159  validCommitments.emplace(hash);
1160 
1163 
1164  quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
1165  status.receivedPrematureCommitment = true;
1166  return true;
1167  });
1168 
1169  int receivedCount = 0;
1170  for (const auto& m : members) {
1171  if (!m->prematureCommitments.empty()) {
1172  receivedCount++;
1173  }
1174  }
1175 
1176  t1.stop();
1177 
1178  logger.Batch("verified premature commitment. received=%d/%d, time=%d", receivedCount, members.size(), t1.count());
1179 }
1180 
1181 std::vector<CFinalCommitment> CDKGSession::FinalizeCommitments()
1182 {
1183  if (!AreWeMember()) {
1184  return {};
1185  }
1186 
1187  CDKGLogger logger(*this, __func__);
1188 
1189  cxxtimer::Timer totalTimer(true);
1190 
1191  std::vector<CBLSPublicKey> allkeys;
1192  for (const auto& m : members) {
1193  allkeys.emplace_back(m->dmn->pdmnState->pubKeyOperator.Get());
1194  }
1195 
1196  typedef std::vector<bool> Key;
1197  std::map<Key, std::vector<CDKGPrematureCommitment>> commitmentsMap;
1198 
1199  for (const auto& p : prematureCommitments) {
1200  auto& qc = p.second;
1201  if (!validCommitments.count(p.first)) {
1202  continue;
1203  }
1204 
1205  // should have been verified before
1206  assert(qc.CountValidMembers() >= params.minSize);
1207 
1208  auto it = commitmentsMap.find(qc.validMembers);
1209  if (it == commitmentsMap.end()) {
1210  it = commitmentsMap.emplace(qc.validMembers, std::vector<CDKGPrematureCommitment>()).first;
1211  }
1212 
1213  it->second.emplace_back(qc);
1214  }
1215 
1216  const CChainParams& chainparams = Params();
1217 
1218  std::vector<CFinalCommitment> finalCommitments;
1219  for (const auto& p : commitmentsMap) {
1220  auto& cvec = p.second;
1221  if (cvec.size() < (size_t)params.minSize) {
1222  // commitment was signed by a minority
1223  continue;
1224  }
1225 
1226  std::vector<CBLSId> signerIds;
1227  std::vector<CBLSSignature> thresholdSigs;
1228 
1229  auto& first = cvec[0];
1230 
1231  CFinalCommitment fqc(params, first.quorumHash);
1232  fqc.validMembers = first.validMembers;
1233  fqc.quorumPublicKey = first.quorumPublicKey;
1234  fqc.quorumVvecHash = first.quorumVvecHash;
1235 
1237 
1238  std::vector<CBLSSignature> aggSigs;
1239  std::vector<CBLSPublicKey> aggPks;
1240  aggSigs.reserve(cvec.size());
1241  aggPks.reserve(cvec.size());
1242 
1243  for (size_t i = 0; i < cvec.size(); i++) {
1244  auto& qc = cvec[i];
1245 
1246  if (qc.quorumPublicKey != first.quorumPublicKey || qc.quorumVvecHash != first.quorumVvecHash) {
1247  logger.Batch("quorumPublicKey or quorumVvecHash does not match, skipping");
1248  continue;
1249  }
1250 
1251  size_t signerIndex = membersMap[qc.proTxHash];
1252  const auto& m = members[signerIndex];
1253 
1254  fqc.signers[signerIndex] = true;
1255  aggSigs.emplace_back(qc.sig);
1256  aggPks.emplace_back(m->dmn->pdmnState->pubKeyOperator.Get());
1257 
1258  signerIds.emplace_back(m->id);
1259  thresholdSigs.emplace_back(qc.quorumSig);
1260  }
1261 
1262  cxxtimer::Timer t1(true);
1263  fqc.membersSig = CBLSSignature::AggregateSecure(aggSigs, aggPks, commitmentHash);
1264  t1.stop();
1265 
1266  cxxtimer::Timer t2(true);
1267  if (!fqc.quorumSig.Recover(thresholdSigs, signerIds)) {
1268  logger.Batch("failed to recover quorum sig");
1269  continue;
1270  }
1271  t2.stop();
1272 
1273  cxxtimer::Timer t3(true);
1274  if (!fqc.Verify(allkeys, params)) {
1275  logger.Batch("failed to verify final commitment");
1276  continue;
1277  }
1278  t3.stop();
1279 
1280  finalCommitments.emplace_back(fqc);
1281 
1282  logger.Batch("final commitment: validMembers=%d, signers=%d, quorumPublicKey=%s, time1=%d, time2=%d, time3=%d, total=%d",
1283  fqc.CountValidMembers(), fqc.CountSigners(), bls::EncodePublic(chainparams, fqc.quorumPublicKey),
1284  t1.count(), t2.count(), t3.count(), totalTimer.count());
1285  }
1286 
1287  totalTimer.stop();
1288  logger.Flush();
1289 
1290  return finalCommitments;
1291 }
1292 
1294 {
1295  auto it = membersMap.find(proTxHash);
1296  if (it == membersMap.end()) {
1297  return nullptr;
1298  }
1299  return members[it->second].get();
1300 }
1301 
1303 {
1304  if (member->bad) {
1305  return;
1306  }
1307  quorumDKGDebugManager->UpdateLocalMemberStatus(params.type, member->idx, [&](CDKGDebugMemberStatus& status) {
1308  status.bad = true;
1309  return true;
1310  });
1311  member->bad = true;
1312 }
1313 
1315 {
1316  LOCK(invCs);
1317  g_connman->ForEachNode([&](CNode* pnode) {
1318  if (!pnode->verifiedProRegTxHash.IsNull() && relayMembers.count(pnode->verifiedProRegTxHash)) {
1319  pnode->PushInventory(inv);
1320  }
1321  });
1322 }
1323 
1324 }
CActiveDeterministicMasternodeManager * activeMasternodeManager
std::shared_ptr< BLSVerificationVector > BLSVerificationVectorPtr
Definition: bls_wrapper.h:415
std::vector< CBLSSecretKey > BLSSecretKeyVector
Definition: bls_wrapper.h:411
const CChainParams & Params()
Return the currently selected parameters.
const CBLSSecretKey * OperatorKey() const
void MakeNewKey()
Definition: bls_wrapper.cpp:54
CBLSPublicKey GetPublicKey() const
Definition: bls_wrapper.cpp:99
CBLSSignature Sign(const uint256 &hash) const
bool VerifyInsecure(const CBLSPublicKey &pubKey, const uint256 &hash) const
static CBLSSignature AggregateSecure(const std::vector< CBLSSignature > &sigs, const std::vector< CBLSPublicKey > &pks, const uint256 &hash)
bool Recover(const std::vector< CBLSSignature > &sigs, const std::vector< CBLSId > &ids)
BLSVerificationVectorPtr BuildQuorumVerificationVector(const uint256 &cacheKey, const std::vector< BLSVerificationVectorPtr > &vvecs)
Definition: bls_worker.h:162
CBLSPublicKey BuildPubKeyShare(const uint256 &cacheKey, const BLSVerificationVectorPtr &vvec, const CBLSId &id)
Definition: bls_worker.h:174
CBLSSecretKey AggregateSecretKeys(const uint256 &cacheKey, const BLSSecretKeyVector &skShares)
Definition: bls_worker.h:168
std::vector< bool > VerifyContributionShares(const CBLSId &forId, const std::vector< BLSVerificationVectorPtr > &vvecs, const BLSSecretKeyVector &skShares, bool parallel=true, bool aggregated=true)
Definition: bls_worker.cpp:753
bool VerifyVerificationVector(const BLSVerificationVector &vvec, size_t start=0, size_t count=0)
Definition: bls_worker.cpp:787
std::future< bool > AsyncVerifyContributionShare(const CBLSId &forId, const BLSVerificationVectorPtr &vvec, const CBLSSecretKey &skContribution)
Definition: bls_worker.cpp:759
bool GenerateContributions(int threshold, const BLSIdVector &ids, BLSVerificationVectorPtr &vvecRet, BLSSecretKeyVector &skShares)
Definition: bls_worker.cpp:77
bool IsValid() const
Definition: bls_wrapper.h:87
void SetByteVector(const std::vector< uint8_t > &vecBytes)
Definition: bls_wrapper.h:97
std::vector< uint8_t > ToByteVector() const
Definition: bls_wrapper.h:116
void Flush()
Definition: logging.cpp:279
void Batch(const std::string &fmt, const Args &... args)
Definition: logging.h:184
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:139
uint256 GetBlockHash() const
Definition: chain.h:215
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
CChainParams defines various tweakable parameters of a given instance of the PIVX system.
Definition: chainparams.h:43
inv message data
Definition: protocol.h:466
CMasternodeMetaInfoPtr GetMetaInfo(const uint256 &proTxHash, bool fCreate=true)
Information about a peer.
Definition: net.h:669
std::atomic< int > nVersion
Definition: net.h:699
uint256 verifiedProRegTxHash
Definition: net.h:802
std::string ToString() const
Definition: uint256.cpp:65
bool IsNull() const
Definition: uint256.h:36
unsigned char * begin()
Definition: uint256.h:63
This class works as a stopwatch.
Definition: cxxtimer.h:37
void stop()
Stop/pause the timer.
Definition: cxxtimer.h:151
duration_t::rep count() const
Return the elapsed time.
Definition: cxxtimer.h:169
uint256 GetSignHash() const
std::vector< bool > badMembers
std::vector< bool > complainForMembers
std::shared_ptr< CBLSIESMultiRecipientObjects< CBLSSecretKey > > contributions
uint256 GetSignHash() const
BLSVerificationVectorPtr vvec
std::vector< std::pair< uint32_t, CBLSSecretKey > > contributions
CDKGLogger(const CDKGSession &_quorumDkg, const std::string &_func)
CDKGMember(CDeterministicMNCPtr _dmn, size_t _idx)
Acts as a FIFO queue for incoming DKG messages.
void PushPendingMessage(NodeId from, CDataStream &vRecv, int invType)
The DKG session is a single instance of the DKG process.
CBLSWorkerCache cache
std::map< uint256, CDKGContribution > contributions
void VerifyAndJustify(CDKGPendingMessages &pendingMessages)
std::map< uint256, CDKGPrematureCommitment > prematureCommitments
std::map< uint256, size_t > membersMap
BLSSecretKeyVector receivedSkContributions
std::vector< std::unique_ptr< CDKGMember > > members
void SendJustification(CDKGPendingMessages &pendingMessages, const std::set< uint256 > &forMembers)
void VerifyAndCommit(CDKGPendingMessages &pendingMessages)
std::map< uint256, CDKGJustification > justifications
std::set< uint256 > relayMembers
bool ShouldSimulateError(const std::string &error_type)
bool AreWeMember() const
CDKGSessionManager & dkgManager
bool PreVerifyMessage(const CDKGContribution &qc, bool &retBan) const
void ReceiveMessage(const uint256 &hash, const CDKGContribution &qc, bool &retBan)
std::map< uint256, CDKGComplaint > complaints
std::vector< CFinalCommitment > FinalizeCommitments()
void Contribute(CDKGPendingMessages &pendingMessages)
The following sets of methods are for the first 4 phases handled in the session.
std::set< uint256 > validCommitments
RecursiveMutex invCs
const Consensus::LLMQParams & params
void MarkBadMember(CDKGMember *member)
void SendCommitment(CDKGPendingMessages &pendingMessages)
const CBlockIndex * pindexQuorum
void SendContributions(CDKGPendingMessages &pendingMessages)
std::vector< BLSVerificationVectorPtr > receivedVvecs
void VerifyAndComplain(CDKGPendingMessages &pendingMessages)
CDKGMember * GetMember(const uint256 &proTxHash) const
BLSSecretKeyVector skContributions
void SendComplaint(CDKGPendingMessages &pendingMessages)
BLSVerificationVectorPtr vvecContribution
void VerifyConnectionAndMinProtoVersions()
void RelayInvToParticipants(const CInv &inv) const
bool Init(const CBlockIndex *_pindexQuorum, const std::vector< CDeterministicMNCPtr > &mns, const uint256 &_myProTxHash)
std::vector< size_t > pendingContributionVerifications
void WriteVerifiedSkContribution(Consensus::LLMQType llmqType, const CBlockIndex *pindexQuorum, const uint256 &proTxHash, const CBLSSecretKey &skContribution)
void WriteVerifiedVvecContribution(Consensus::LLMQType llmqType, const CBlockIndex *pindexQuorum, const uint256 &proTxHash, const BLSVerificationVectorPtr &vvec)
bool GetVerifiedContributions(Consensus::LLMQType llmqType, const CBlockIndex *pindexQuorum, const std::vector< bool > &validMembers, std::vector< uint16_t > &memberIndexesRet, std::vector< BLSVerificationVectorPtr > &vvecsRet, BLSSecretKeyVector &skContributionsRet)
bool Verify(const std::vector< CBLSPublicKey > &allkeys, const Consensus::LLMQParams &params) const
std::vector< bool > validMembers
std::vector< bool > signers
256-bit opaque blob.
Definition: uint256.h:138
std::shared_ptr< const CDeterministicMN > CDeterministicMNCPtr
uint256 SerializeHash(const T &obj, int nType=SER_GETHASH, int nVersion=PROTOCOL_VERSION)
Compute the 256-bit hash of an object's serialization.
Definition: hash.h:289
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:90
@ LOCK
Definition: lockunlock.h:16
BCLog::Logger *const g_logger
NOTE: the logger instances is leaked on exit.
Definition: logging.cpp:26
#define LogPrint(category,...)
Definition: logging.h:163
CMasternodeMetaMan g_mmetaman
Definition: logging.h:38
@ DKG
Definition: logging.h:68
LLMQType
Definition: params.h:90
@ LLMQ_TEST
Definition: params.h:98
std::string EncodePublic(const CChainParams &params, const CBLSPublicKey &pk)
Definition: key_io.cpp:55
uint256 BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256 &blockHash, const std::vector< bool > &validMembers, const CBLSPublicKey &pubKey, const uint256 &vvecHash)
Definition: quorums.cpp:26
std::unique_ptr< CDKGDebugManager > quorumDKGDebugManager
bool SetSimulatedDKGErrorRate(const std::string &error_type, double rate)
std::set< uint256 > GetQuorumRelayMembers(const std::vector< CDeterministicMNCPtr > &mnList, unsigned int forMemberIndex)
@ MSG_QUORUM_JUSTIFICATION
Definition: protocol.h:457
@ MSG_QUORUM_COMPLAINT
Definition: protocol.h:456
@ MSG_QUORUM_CONTRIB
Definition: protocol.h:455
@ MSG_QUORUM_PREMATURE_COMMITMENT
Definition: protocol.h:458
bool GetRandBool(double rate) noexcept
Definition: random.cpp:603
int GetRandInt(int nMax) noexcept
Definition: random.cpp:591
const char * name
Definition: rest.cpp:37
@ proTxHash
Definition: rpcevo.cpp:50
Definition: bls_dkg.cpp:20
int64_t GetAdjustedTime()
Definition: timedata.cpp:36
#define strprintf
Definition: tinyformat.h:1056