Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

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