LCOV - code coverage report
Current view: top level - src/active - dkgsession.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 417 448 93.1 %
Date: 2026-06-25 07:23:43 Functions: 24 24 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2018-2025 The Dash Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <active/dkgsession.h>
       6             : 
       7             : #include <active/masternode.h>
       8             : #include <evo/deterministicmns.h>
       9             : #include <llmq/commitment.h>
      10             : #include <llmq/debug.h>
      11             : #include <llmq/dkgsessionhandler.h>
      12             : #include <llmq/dkgsessionmgr.h>
      13             : #include <llmq/options.h>
      14             : #include <llmq/utils.h>
      15             : #include <masternode/meta.h>
      16             : #include <util/helpers.h>
      17             : 
      18             : #include <chain.h>
      19             : #include <deploymentstatus.h>
      20             : #include <validation.h>
      21             : 
      22             : #include <cxxtimer.hpp>
      23             : 
      24             : namespace llmq {
      25       22084 : ActiveDKGSession::ActiveDKGSession(CBLSWorker& bls_worker, CDeterministicMNManager& dmnman, CDKGDebugManager& dkgdbgman,
      26             :                                    CDKGSessionManager& qdkgsman, CMasternodeMetaMan& mn_metaman,
      27             :                                    CQuorumSnapshotManager& qsnapman, const CActiveMasternodeManager& mn_activeman,
      28             :                                    const ChainstateManager& chainman, const CSporkManager& sporkman,
      29             :                                    const CBlockIndex* base_block_index, const Consensus::LLMQParams& llmq_params) :
      30       11042 :     CDKGSession(bls_worker, dmnman, dkgdbgman, qdkgsman, qsnapman, chainman, base_block_index, llmq_params),
      31       11042 :     m_mn_metaman{mn_metaman},
      32       11042 :     m_mn_activeman{mn_activeman},
      33       11042 :     m_sporkman{sporkman},
      34       11042 :     m_use_legacy_bls{!DeploymentActiveAfter(m_quorum_base_block_index, Params().GetConsensus(), Consensus::DEPLOYMENT_V19)}
      35       22084 : {
      36       22084 : }
      37             : 
      38       33127 : ActiveDKGSession::~ActiveDKGSession() = default;
      39             : 
      40        4238 : std::optional<CDKGContribution> ActiveDKGSession::Contribute()
      41             : {
      42        4238 :     if (!AreWeMember()) {
      43        1634 :         return std::nullopt;
      44             :     }
      45             : 
      46        2604 :     assert(params.threshold > 1); // we should not get there with single-node-quorums
      47             : 
      48        2604 :     CDKGLogger logger(*this, __func__, __LINE__);
      49             : 
      50        2604 :     cxxtimer::Timer t1(true);
      51        2604 :     logger.Batch("generating contributions");
      52        2604 :     if (!blsWorker.GenerateContributions(params.threshold, memberIds, vvecContribution, m_sk_contributions)) {
      53             :         // this should never happen actually
      54           0 :         logger.Batch("GenerateContributions failed");
      55           0 :         return std::nullopt;
      56             :     }
      57        2604 :     logger.Batch("generated contributions. time=%d", t1.count());
      58        2604 :     logger.Flush();
      59             : 
      60        2604 :     return SendContributions();
      61        4238 : }
      62             : 
      63        2606 : std::optional<CDKGContribution> ActiveDKGSession::SendContributions()
      64             : {
      65        2606 :     CDKGLogger logger(*this, __func__, __LINE__);
      66             : 
      67        2606 :     assert(AreWeMember());
      68             : 
      69        2604 :     logger.Batch("sending contributions");
      70             : 
      71        2604 :     if (ShouldSimulateError(DKGError::type::CONTRIBUTION_OMIT)) {
      72           2 :         logger.Batch("omitting");
      73           2 :         return std::nullopt;
      74             :     }
      75             : 
      76        2602 :     CDKGContribution qc;
      77        2604 :     qc.llmqType = params.type;
      78        2604 :     qc.quorumHash = m_quorum_base_block_index->GetBlockHash();
      79        2602 :     qc.proTxHash = myProTxHash;
      80        2602 :     qc.vvec = vvecContribution;
      81             : 
      82        2602 :     cxxtimer::Timer t1(true);
      83        2602 :     qc.contributions = std::make_shared<CBLSIESMultiRecipientObjects<CBLSSecretKey>>();
      84        2601 :     qc.contributions->InitEncrypt(members.size());
      85             : 
      86       12382 :     for (const auto i : util::irange(members.size())) {
      87        9780 :         const auto& m = members[i];
      88        9780 :         CBLSSecretKey skContrib = m_sk_contributions[i];
      89             : 
      90        9780 :         if (i != myIdx && ShouldSimulateError(DKGError::type::CONTRIBUTION_LIE)) {
      91          12 :             logger.Batch("lying for %s", m->dmn->proTxHash.ToString());
      92          12 :             skContrib.MakeNewKey();
      93          12 :         }
      94             : 
      95        9780 :         if (!qc.contributions->Encrypt(i, m->dmn->pdmnState->pubKeyOperator.Get(), skContrib, PROTOCOL_VERSION)) {
      96           0 :             logger.Batch("failed to encrypt contribution for %s", m->dmn->proTxHash.ToString());
      97           0 :             return std::nullopt;
      98             :         }
      99        9780 :     }
     100             : 
     101        2602 :     logger.Batch("encrypted contributions. time=%d", t1.count());
     102             : 
     103        2602 :     qc.sig = m_mn_activeman.Sign(qc.GetSignHash(), m_use_legacy_bls);
     104             : 
     105        2602 :     logger.Flush();
     106             : 
     107        5204 :     dkgDebugManager.UpdateLocalSessionStatus(params.type, quorumIndex, [&](CDKGDebugSessionStatus& status) {
     108        2602 :         status.statusBits.sentContributions = true;
     109        2602 :         return true;
     110             :     });
     111             : 
     112        2602 :     return qc;
     113        2612 : }
     114             : 
     115             : // Verifies all pending secret key contributions in one batch
     116             : // This is done by aggregating the verification vectors belonging to the secret key contributions
     117             : // The resulting aggregated vvec is then used to recover a public key share
     118             : // The public key share must match the public key belonging to the aggregated secret key contributions
     119             : // See CBLSWorker::VerifyContributionShares for more details.
     120        2468 : void ActiveDKGSession::VerifyPendingContributions()
     121             : {
     122        2468 :     AssertLockHeld(cs_pending);
     123             : 
     124        2468 :     CDKGLogger logger(*this, __func__, __LINE__);
     125             : 
     126        2468 :     cxxtimer::Timer t1(true);
     127             : 
     128        2468 :     if (pendingContributionVerifications.empty()) {
     129          24 :         return;
     130             :     }
     131             : 
     132        2444 :     std::vector<size_t> memberIndexes;
     133        2444 :     std::vector<BLSVerificationVectorPtr> vvecs;
     134        2444 :     std::vector<CBLSSecretKey> skContributions;
     135             : 
     136       11093 :     for (const auto& idx : pendingContributionVerifications) {
     137        8655 :         const auto& m = members[idx];
     138        8655 :         if (m->bad || m->weComplain) {
     139          14 :             continue;
     140             :         }
     141        8655 :         memberIndexes.emplace_back(idx);
     142        8649 :         vvecs.emplace_back(receivedVvecs[idx]);
     143        8649 :         skContributions.emplace_back(receivedSkContributions[idx]);
     144             :         // Write here to definitely store one contribution for each member no matter if
     145             :         // our share is valid or not, could be that others are still correct
     146        8649 :         dkgManager.WriteEncryptedContributions(params.type, m_quorum_base_block_index, m->dmn->proTxHash, *vecEncryptedContributions[idx]);
     147             :     }
     148             : 
     149        2438 :     auto result = blsWorker.VerifyContributionShares(myId, vvecs, skContributions);
     150        2444 :     if (result.size() != memberIndexes.size()) {
     151           6 :         logger.Batch("VerifyContributionShares returned result of size %d but size %d was expected, something is wrong", result.size(), memberIndexes.size());
     152           0 :         return;
     153             :     }
     154             : 
     155       11087 :     for (const auto i : util::irange(memberIndexes.size())) {
     156        8648 :         if (!result[i]) {
     157          12 :             const auto& m = members[memberIndexes[i]];
     158          12 :             logger.Batch("invalid contribution from %s. will complain later", m->dmn->proTxHash.ToString());
     159          12 :             m->weComplain = true;
     160          24 :             dkgDebugManager.UpdateLocalMemberStatus(params.type, quorumIndex, m->idx, [&](CDKGDebugMemberStatus& status) {
     161          12 :                 status.statusBits.weComplain = true;
     162          12 :                 return true;
     163             :             });
     164          12 :         } else {
     165        8635 :             size_t memberIdx = memberIndexes[i];
     166        8635 :             dkgManager.WriteVerifiedSkContribution(params.type, m_quorum_base_block_index, members[memberIdx]->dmn->proTxHash, skContributions[i]);
     167             :         }
     168             :     }
     169             : 
     170        2438 :     logger.Batch("verified %d pending contributions. time=%d", pendingContributionVerifications.size(), t1.count());
     171        2438 :     pendingContributionVerifications.clear();
     172        2486 : }
     173             : 
     174        4039 : std::optional<CDKGComplaint> ActiveDKGSession::VerifyAndComplain(CConnman& connman)
     175             : {
     176        4039 :     if (!AreWeMember()) {
     177        1577 :         return std::nullopt;
     178             :     }
     179             : 
     180             :     {
     181        2462 :         LOCK(cs_pending);
     182        2462 :         VerifyPendingContributions();
     183        2462 :     }
     184             : 
     185        2462 :     CDKGLogger logger(*this, __func__, __LINE__);
     186             : 
     187             :     // we check all members if they sent us their contributions
     188             :     // we consider members as bad if they missed to send anything or if they sent multiple
     189             :     // in both cases we won't give them a second chance as they might be either down, buggy or an adversary
     190             :     // we assume that such a participant will be marked as bad by the whole network in most cases,
     191             :     // as propagation will ensure that all nodes see the same vvecs/contributions. In case nodes come to
     192             :     // different conclusions, the aggregation phase will handle this (most voted quorum key wins).
     193             : 
     194        2462 :     cxxtimer::Timer t1(true);
     195             : 
     196       11765 :     for (const auto& m : members) {
     197        9303 :         if (m->bad) {
     198           0 :             continue;
     199             :         }
     200        9303 :         if (m->contributions.empty()) {
     201         650 :             logger.Batch("%s did not send any contribution", m->dmn->proTxHash.ToString());
     202         650 :             MarkBadMember(m->idx);
     203         650 :             continue;
     204             :         }
     205             :     }
     206             : 
     207        2462 :     logger.Batch("verified contributions. time=%d", t1.count());
     208        2462 :     logger.Flush();
     209             : 
     210        2462 :     VerifyConnectionAndMinProtoVersions(connman);
     211             : 
     212        2462 :     return SendComplaint();
     213        4039 : }
     214             : 
     215        2462 : void ActiveDKGSession::VerifyConnectionAndMinProtoVersions(CConnman& connman) const
     216             : {
     217        2462 :     assert(m_mn_metaman.IsValid());
     218             : 
     219        2462 :     if (!IsQuorumPoseEnabled(params.type, m_sporkman)) {
     220        2063 :         return;
     221             :     }
     222             : 
     223         399 :     CDKGLogger logger(*this, __func__, __LINE__);
     224             : 
     225         399 :     Uint256HashMap<int> protoMap;
     226        2366 :     connman.ForEachNode([&](const CNode* pnode) {
     227        1967 :         auto verifiedProRegTxHash = pnode->GetVerifiedProRegTxHash();
     228        1967 :         if (verifiedProRegTxHash.IsNull()) {
     229         412 :             return;
     230             :         }
     231        1555 :         protoMap.emplace(verifiedProRegTxHash, pnode->nVersion);
     232        1967 :     });
     233             : 
     234         399 :     bool fShouldAllMembersBeConnected = IsAllMembersConnectedEnabled(params.type, m_sporkman);
     235        2055 :     for (const auto& m : members) {
     236        1656 :         if (m->dmn->proTxHash == myProTxHash) {
     237         399 :             continue;
     238             :         }
     239        1257 :         if (auto it = protoMap.find(m->dmn->proTxHash); it == protoMap.end()) {
     240          45 :             m->badConnection = fShouldAllMembersBeConnected;
     241          45 :             if (m->badConnection) {
     242           1 :                 logger.Batch("%s is not connected to us, badConnection=1", m->dmn->proTxHash.ToString());
     243           1 :             }
     244        1257 :         } else if (it->second < MIN_MASTERNODE_PROTO_VERSION) {
     245          17 :             m->badConnection = true;
     246          17 :             logger.Batch("%s does not have min proto version %d (has %d)", m->dmn->proTxHash.ToString(), MIN_MASTERNODE_PROTO_VERSION, it->second);
     247          17 :         }
     248        1257 :         if (m_mn_metaman.OutboundFailedTooManyTimes(m->dmn->proTxHash)) {
     249         103 :             m->badConnection = true;
     250         103 :             logger.Batch("%s failed to connect to it too many times", m->dmn->proTxHash.ToString());
     251         103 :         }
     252        1257 :         if (m_mn_metaman.IsPlatformBanned(m->dmn->proTxHash)) {
     253           8 :             m->badConnection = true;
     254           8 :             logger.Batch("%s is Platform PoSe banned", m->dmn->proTxHash.ToString());
     255           8 :         }
     256             :     }
     257        2462 : }
     258             : 
     259        2462 : std::optional<CDKGComplaint> ActiveDKGSession::SendComplaint()
     260             : {
     261        2462 :     CDKGLogger logger(*this, __func__, __LINE__);
     262             : 
     263        2462 :     assert(AreWeMember());
     264             : 
     265        2462 :     CDKGComplaint qc(params);
     266        2462 :     qc.llmqType = params.type;
     267        2462 :     qc.quorumHash = m_quorum_base_block_index->GetBlockHash();
     268        2462 :     qc.proTxHash = myProTxHash;
     269             : 
     270        2462 :     int badCount = 0;
     271        2462 :     int complaintCount = 0;
     272       11765 :     for (const auto i : util::irange(members.size())) {
     273        9303 :         const auto& m = members[i];
     274        9303 :         if (m->bad || m->badConnection) {
     275         750 :             qc.badMembers[i] = true;
     276         750 :             badCount++;
     277        9303 :         } else if (m->weComplain) {
     278          16 :             qc.complainForMembers[i] = true;
     279          16 :             complaintCount++;
     280          16 :         }
     281             :     }
     282             : 
     283        2462 :     if (badCount == 0 && complaintCount == 0) {
     284        1928 :         return std::nullopt;
     285             :     }
     286             : 
     287         534 :     logger.Batch("sending complaint. badCount=%d, complaintCount=%d", badCount, complaintCount);
     288             : 
     289         534 :     qc.sig = m_mn_activeman.Sign(qc.GetSignHash(), m_use_legacy_bls);
     290             : 
     291         534 :     logger.Flush();
     292             : 
     293        1068 :     dkgDebugManager.UpdateLocalSessionStatus(params.type, quorumIndex, [&](CDKGDebugSessionStatus& status) {
     294         534 :         status.statusBits.sentComplaint = true;
     295         534 :         return true;
     296             :     });
     297             : 
     298         534 :     return qc;
     299        2462 : }
     300             : 
     301        3938 : std::optional<CDKGJustification> ActiveDKGSession::VerifyAndJustify()
     302             : {
     303        3938 :     if (!AreWeMember()) {
     304        1554 :         return std::nullopt;
     305             :     }
     306             : 
     307        2384 :     CDKGLogger logger(*this, __func__, __LINE__);
     308             : 
     309        2384 :     Uint256HashSet justifyFor;
     310             : 
     311       11430 :     for (const auto& m : members) {
     312        9046 :         if (m->bad) {
     313         493 :             continue;
     314             :         }
     315        8553 :         if (m->badMemberVotes.size() >= size_t(params.dkgBadVotesThreshold)) {
     316         134 :             logger.Batch("%s marked as bad as %d other members voted for this", m->dmn->proTxHash.ToString(), m->badMemberVotes.size());
     317         134 :             MarkBadMember(m->idx);
     318         134 :             continue;
     319             :         }
     320        8419 :         if (m->complaints.empty()) {
     321        7137 :             continue;
     322             :         }
     323        1282 :         if (m->complaints.size() != 1) {
     324           0 :             logger.Batch("%s sent multiple complaints", m->dmn->proTxHash.ToString());
     325           0 :             MarkBadMember(m->idx);
     326           0 :             continue;
     327             :         }
     328             : 
     329        1282 :         LOCK(invCs);
     330        1282 :         if (const auto& qc = complaints.at(*m->complaints.begin());
     331        1282 :                 qc.complainForMembers[*myIdx]) {
     332          16 :             justifyFor.emplace(qc.proTxHash);
     333          16 :         }
     334        1282 :     }
     335             : 
     336        2384 :     logger.Flush();
     337        2384 :     if (justifyFor.empty()) {
     338        2374 :         return std::nullopt;
     339             :     }
     340          10 :     return SendJustification(justifyFor);
     341        3938 : }
     342             : 
     343          10 : std::optional<CDKGJustification> ActiveDKGSession::SendJustification(const Uint256HashSet& forMembers)
     344             : {
     345          10 :     CDKGLogger logger(*this, __func__, __LINE__);
     346             : 
     347          10 :     assert(AreWeMember());
     348             : 
     349          10 :     logger.Batch("sending justification for %d members", forMembers.size());
     350             : 
     351          10 :     CDKGJustification qj;
     352          10 :     qj.llmqType = params.type;
     353          10 :     qj.quorumHash = m_quorum_base_block_index->GetBlockHash();
     354          10 :     qj.proTxHash = myProTxHash;
     355          10 :     qj.contributions.reserve(forMembers.size());
     356             : 
     357          40 :     for (const uint32_t i : util::irange(members.size())) {
     358          30 :         const auto& m = members[i];
     359          30 :         if (forMembers.count(m->dmn->proTxHash) == 0) {
     360          14 :             continue;
     361             :         }
     362          16 :         logger.Batch("justifying for %s", m->dmn->proTxHash.ToString());
     363             : 
     364          16 :         CBLSSecretKey skContribution = m_sk_contributions[i];
     365             : 
     366          16 :         if (i != myIdx && ShouldSimulateError(DKGError::type::JUSTIFY_LIE)) {
     367           4 :             logger.Batch("lying for %s", m->dmn->proTxHash.ToString());
     368           4 :             skContribution.MakeNewKey();
     369           4 :         }
     370             : 
     371          16 :         qj.contributions.emplace_back(CDKGJustification::Contribution{i, skContribution});
     372          16 :     }
     373             : 
     374          10 :     if (ShouldSimulateError(DKGError::type::JUSTIFY_OMIT)) {
     375           2 :         logger.Batch("omitting");
     376           2 :         return std::nullopt;
     377             :     }
     378             : 
     379           8 :     qj.sig = m_mn_activeman.Sign(qj.GetSignHash(), m_use_legacy_bls);
     380             : 
     381           8 :     logger.Flush();
     382             : 
     383          16 :     dkgDebugManager.UpdateLocalSessionStatus(params.type, quorumIndex, [&](CDKGDebugSessionStatus& status) {
     384           8 :         status.statusBits.sentJustification = true;
     385           8 :         return true;
     386             :     });
     387             : 
     388           8 :     return qj;
     389          10 : }
     390             : 
     391        3868 : std::optional<CDKGPrematureCommitment> ActiveDKGSession::VerifyAndCommit()
     392             : {
     393        3868 :     if (!AreWeMember()) {
     394        1524 :         return std::nullopt;
     395             :     }
     396             : 
     397        2344 :     CDKGLogger logger(*this, __func__, __LINE__);
     398             : 
     399        2344 :     std::vector<size_t> badMembers;
     400        2344 :     badMembers.reserve(members.size());
     401        2344 :     std::vector<size_t> openComplaintMembers;
     402        2344 :     openComplaintMembers.reserve(members.size());
     403             : 
     404       11201 :     for (const auto& m : members) {
     405        8869 :         if (m->bad) {
     406         606 :             badMembers.emplace_back(m->idx);
     407         606 :             continue;
     408             :         }
     409        8263 :         if (!m->complaintsFromOthers.empty()) {
     410           6 :             MarkBadMember(m->idx);
     411           6 :             openComplaintMembers.emplace_back(m->idx);
     412           6 :         }
     413             :     }
     414             : 
     415        2332 :     if (!badMembers.empty() || !openComplaintMembers.empty()) {
     416         453 :         logger.Batch("verification result:");
     417         459 :     }
     418        2338 :     if (!badMembers.empty()) {
     419         453 :         logger.Batch("  members previously determined as bad:");
     420        1059 :         for (const auto& idx : badMembers) {
     421         606 :             logger.Batch("    %s", members[idx]->dmn->proTxHash.ToString());
     422             :         }
     423         453 :     }
     424        2338 :     if (!openComplaintMembers.empty()) {
     425           6 :         logger.Batch("  members with open complaints and now marked as bad:");
     426          12 :         for (const auto& idx : openComplaintMembers) {
     427           6 :             logger.Batch("    %s", members[idx]->dmn->proTxHash.ToString());
     428             :         }
     429           6 :     }
     430             : 
     431        2338 :     logger.Flush();
     432             : 
     433        2332 :     return SendCommitment();
     434        3880 : }
     435             : 
     436        2336 : std::optional<CDKGPrematureCommitment> ActiveDKGSession::SendCommitment()
     437             : {
     438        2336 :     CDKGLogger logger(*this, __func__, __LINE__);
     439             : 
     440        2336 :     assert(AreWeMember());
     441             : 
     442        2332 :     logger.Batch("sending commitment");
     443             : 
     444        2332 :     CDKGPrematureCommitment qc(params);
     445        2336 :     qc.llmqType = params.type;
     446        2336 :     qc.quorumHash = m_quorum_base_block_index->GetBlockHash();
     447        2332 :     qc.proTxHash = myProTxHash;
     448             : 
     449       11198 :     for (const auto i : util::irange(members.size())) {
     450        8865 :         const auto& m = members[i];
     451        8865 :         if (!m->bad) {
     452        8253 :             qc.validMembers[i] = true;
     453        8254 :         }
     454             :     }
     455             : 
     456        2331 :     if (qc.CountValidMembers() < params.minSize) {
     457         315 :         logger.Batch("not enough valid members. not sending commitment");
     458         315 :         return std::nullopt;
     459             :     }
     460             : 
     461        2017 :     if (ShouldSimulateError(DKGError::type::COMMIT_OMIT)) {
     462           2 :         logger.Batch("omitting");
     463           2 :         return std::nullopt;
     464             :     }
     465             : 
     466        2015 :     cxxtimer::Timer timerTotal(true);
     467             : 
     468        2015 :     cxxtimer::Timer t1(true);
     469        2015 :     std::vector<uint16_t> memberIndexes;
     470        2015 :     std::vector<BLSVerificationVectorPtr> vvecs;
     471        2015 :     std::vector<CBLSSecretKey> skContributions;
     472        2015 :     if (!dkgManager.GetVerifiedContributions(params.type, m_quorum_base_block_index, qc.validMembers, memberIndexes, vvecs, skContributions)) {
     473           0 :         logger.Batch("failed to get valid contributions");
     474           0 :         return std::nullopt;
     475             :     }
     476             : 
     477        2015 :     BLSVerificationVectorPtr vvec = cache.BuildQuorumVerificationVector(::SerializeHash(memberIndexes), vvecs);
     478        2015 :     if (vvec == nullptr) {
     479           0 :         logger.Batch("failed to build quorum verification vector");
     480           0 :         return std::nullopt;
     481             :     }
     482        2015 :     t1.stop();
     483             : 
     484        2015 :     cxxtimer::Timer t2(true);
     485        2015 :     CBLSSecretKey skShare = cache.AggregateSecretKeys(::SerializeHash(memberIndexes), skContributions);
     486        2015 :     if (!skShare.IsValid()) {
     487           0 :         logger.Batch("failed to build own secret share");
     488           0 :         return std::nullopt;
     489             :     }
     490        2015 :     t2.stop();
     491             : 
     492        2015 :     logger.Batch("pubKeyShare=%s", skShare.GetPublicKey().ToString());
     493             : 
     494        2015 :     cxxtimer::Timer t3(true);
     495        2015 :     qc.quorumPublicKey = (*vvec)[0];
     496        2015 :     qc.quorumVvecHash = ::SerializeHash(*vvec);
     497             : 
     498        2015 :     int lieType = -1;
     499        2015 :     if (ShouldSimulateError(DKGError::type::COMMIT_LIE)) {
     500           2 :         lieType = GetRand<int>(/*nMax=*/5);
     501           2 :         logger.Batch("lying on commitment. lieType=%d", lieType);
     502           2 :     }
     503             : 
     504        2015 :     if (lieType == 0) {
     505           0 :         CBLSSecretKey k;
     506           0 :         k.MakeNewKey();
     507           0 :         qc.quorumPublicKey = k.GetPublicKey();
     508        2015 :     } else if (lieType == 1) {
     509           0 :         (*qc.quorumVvecHash.begin())++;
     510           0 :     }
     511             : 
     512        2015 :     uint256 commitmentHash = BuildCommitmentHash(qc.llmqType, qc.quorumHash, qc.validMembers, qc.quorumPublicKey, qc.quorumVvecHash);
     513             : 
     514        2015 :     if (lieType == 2) {
     515           1 :         (*commitmentHash.begin())++;
     516           1 :     }
     517             : 
     518        2015 :     qc.sig = m_mn_activeman.Sign(commitmentHash, m_use_legacy_bls);
     519        2015 :     qc.quorumSig = skShare.Sign(commitmentHash, m_use_legacy_bls);
     520             : 
     521        2015 :     if (lieType == 3) {
     522           0 :         auto buf = qc.sig.ToBytes(m_use_legacy_bls);
     523           0 :         buf[5]++;
     524           0 :         qc.sig.SetBytes(buf, m_use_legacy_bls);
     525        2015 :     } else if (lieType == 4) {
     526           1 :         auto buf = qc.quorumSig.ToBytes(m_use_legacy_bls);
     527           1 :         buf[5]++;
     528           1 :         qc.quorumSig.SetBytes(buf, m_use_legacy_bls);
     529           1 :     }
     530             : 
     531        2015 :     t3.stop();
     532        2015 :     timerTotal.stop();
     533             : 
     534        4030 :     logger.Batch("built premature commitment. time1=%d, time2=%d, time3=%d, totalTime=%d",
     535        2015 :                     t1.count(), t2.count(), t3.count(), timerTotal.count());
     536             : 
     537             : 
     538        2015 :     logger.Flush();
     539             : 
     540        4030 :     dkgDebugManager.UpdateLocalSessionStatus(params.type, quorumIndex, [&](CDKGDebugSessionStatus& status) {
     541        2015 :         status.statusBits.sentPrematureCommitment = true;
     542        2015 :         return true;
     543             :     });
     544             : 
     545        2015 :     return qc;
     546        2348 : }
     547             : 
     548        3747 : std::vector<CFinalCommitment> ActiveDKGSession::FinalizeCommitments()
     549             : {
     550        3747 :     if (!AreWeMember()) {
     551        1477 :         return {};
     552             :     }
     553             : 
     554        2270 :     CDKGLogger logger(*this, __func__, __LINE__);
     555             : 
     556             :     using Key = std::vector<bool>;
     557        2270 :     std::map<Key, std::vector<CDKGPrematureCommitment>> commitmentsMap;
     558             : 
     559             :     {
     560        2270 :         LOCK(invCs);
     561             : 
     562        9610 :         for (const auto& p : prematureCommitments) {
     563        7342 :             const auto& qc = p.second;
     564        7342 :             if (validCommitments.count(p.first) == 0) {
     565           0 :                 continue;
     566             :             }
     567             : 
     568             :             // should have been verified before
     569        7342 :             assert(qc.CountValidMembers() >= params.minSize);
     570             : 
     571        7343 :             auto it = commitmentsMap.find(qc.validMembers);
     572        7343 :             if (it == commitmentsMap.end()) {
     573        2065 :                 it = commitmentsMap.emplace(qc.validMembers, std::vector<CDKGPrematureCommitment>()).first;
     574        2065 :             }
     575             : 
     576        7342 :             it->second.emplace_back(qc);
     577             :         }
     578        2264 :     }
     579             : 
     580        2264 :     std::vector<CFinalCommitment> finalCommitments;
     581        4329 :     for (const auto& p : commitmentsMap) {
     582        2079 :         const auto& cvec = p.second;
     583        2079 :         if (cvec.size() < size_t(params.minSize)) {
     584             :             // commitment was signed by a minority
     585         214 :             continue;
     586             :         }
     587             : 
     588        1865 :         std::vector<CBLSId> signerIds;
     589        1865 :         std::vector<CBLSSignature> thresholdSigs;
     590             : 
     591        1865 :         const auto& first = cvec[0];
     592             : 
     593        1865 :         CFinalCommitment fqc(params, first.quorumHash);
     594        1865 :         fqc.validMembers = first.validMembers;
     595        1850 :         fqc.quorumPublicKey = first.quorumPublicKey;
     596        1850 :         fqc.quorumVvecHash = first.quorumVvecHash;
     597             : 
     598        1850 :         const bool isQuorumRotationEnabled{IsQuorumRotationEnabled(params, m_quorum_base_block_index)};
     599             :         // TODO: always put `true` here: so far as v19 is activated, we always write BASIC now
     600        1849 :         fqc.nVersion = CFinalCommitment::GetVersion(isQuorumRotationEnabled, DeploymentActiveAfter(m_quorum_base_block_index, m_chainman.GetConsensus(), Consensus::DEPLOYMENT_V19));
     601        1849 :         fqc.quorumIndex = isQuorumRotationEnabled ? quorumIndex : 0;
     602             : 
     603        1849 :         uint256 commitmentHash = BuildCommitmentHash(fqc.llmqType, fqc.quorumHash, fqc.validMembers, fqc.quorumPublicKey, fqc.quorumVvecHash);
     604             : 
     605        1859 :         std::vector<CBLSSignature> aggSigs;
     606        1859 :         std::vector<CBLSPublicKey> aggPks;
     607        1859 :         aggSigs.reserve(cvec.size());
     608        1850 :         aggPks.reserve(cvec.size());
     609             : 
     610        8755 :         for (const auto& qc : cvec) {
     611        6904 :             if (qc.quorumPublicKey != first.quorumPublicKey || qc.quorumVvecHash != first.quorumVvecHash) {
     612           1 :                 logger.Batch("quorumPublicKey or quorumVvecHash does not match, skipping");
     613           0 :                 continue;
     614             :             }
     615             : 
     616        6904 :             size_t signerIndex = membersMap[qc.proTxHash];
     617        6905 :             const auto& m = members[signerIndex];
     618             : 
     619        6905 :             fqc.signers[signerIndex] = true;
     620        6905 :             aggSigs.emplace_back(qc.sig);
     621        6904 :             aggPks.emplace_back(m->dmn->pdmnState->pubKeyOperator.Get());
     622             : 
     623        6903 :             signerIds.emplace_back(m->id);
     624        6904 :             thresholdSigs.emplace_back(qc.quorumSig);
     625             :         }
     626             : 
     627        1851 :         cxxtimer::Timer t1(true);
     628        1851 :         fqc.membersSig = CBLSSignature::AggregateSecure(aggSigs, aggPks, commitmentHash);
     629        1851 :         t1.stop();
     630             : 
     631        1851 :         cxxtimer::Timer t2(true);
     632        1851 :         if (!fqc.quorumSig.Recover(thresholdSigs, signerIds)) {
     633           0 :             logger.Batch("failed to recover quorum sig");
     634           0 :             continue;
     635             :         }
     636        1851 :         t2.stop();
     637             : 
     638        1851 :         cxxtimer::Timer t3(true);
     639        1851 :         if (!fqc.Verify({m_dmnman, m_qsnapman, m_chainman, m_quorum_base_block_index}, true)) {
     640           0 :             logger.Batch("failed to verify final commitment");
     641           0 :             continue;
     642             :         }
     643        1851 :         t3.stop();
     644             : 
     645        1851 :         finalCommitments.emplace_back(fqc);
     646             : 
     647        3702 :         logger.Batch("final commitment: validMembers=%d, signers=%d, quorumPublicKey=%s, time1=%d, time2=%d, time3=%d",
     648        1851 :                         fqc.CountValidMembers(), fqc.CountSigners(), fqc.quorumPublicKey.ToString(),
     649        1851 :                         t1.count(), t2.count(), t3.count());
     650        1851 :     }
     651             : 
     652        2250 :     logger.Flush();
     653             : 
     654        2250 :     return finalCommitments;
     655        3855 : }
     656             : 
     657          64 : CFinalCommitment ActiveDKGSession::FinalizeSingleCommitment()
     658             : {
     659          64 :     if (!AreWeMember()) {
     660          31 :         return {};
     661             :     }
     662             : 
     663          33 :     CDKGLogger logger(*this, __func__, __LINE__);
     664             : 
     665          33 :     std::vector<CBLSId> signerIds;
     666          33 :     std::vector<CBLSSignature> thresholdSigs;
     667             : 
     668          33 :     CFinalCommitment fqc(params, m_quorum_base_block_index->GetBlockHash());
     669             : 
     670             : 
     671          33 :     fqc.signers = {true};
     672          33 :     fqc.validMembers = {true};
     673             : 
     674          33 :     CBLSSecretKey sk1;
     675          33 :     sk1.MakeNewKey();
     676             : 
     677          33 :     fqc.quorumPublicKey = sk1.GetPublicKey();
     678          33 :     fqc.quorumVvecHash = {};
     679             : 
     680             :     // use just MN's operator public key as quorum pubkey.
     681             :     // TODO: use sk1 here instead and use recovery mechanism from shares, but that's not trivial to do
     682          33 :     const bool workaround_qpublic_key = true;
     683             :     if (workaround_qpublic_key) {
     684          33 :         fqc.quorumPublicKey = m_mn_activeman.GetPubKey();
     685             :     }
     686          33 :     const bool isQuorumRotationEnabled{false};
     687          33 :     fqc.nVersion = CFinalCommitment::GetVersion(isQuorumRotationEnabled,
     688          33 :                                                 DeploymentActiveAfter(m_quorum_base_block_index, m_chainman.GetConsensus(),
     689             :                                                                       Consensus::DEPLOYMENT_V19));
     690          33 :     fqc.quorumIndex = 0;
     691             : 
     692          66 :     uint256 commitmentHash = BuildCommitmentHash(fqc.llmqType, fqc.quorumHash, fqc.validMembers, fqc.quorumPublicKey,
     693          33 :                                                  fqc.quorumVvecHash);
     694          33 :     fqc.quorumSig = sk1.Sign(commitmentHash, m_use_legacy_bls);
     695             : 
     696          33 :     fqc.membersSig = m_mn_activeman.Sign(commitmentHash, m_use_legacy_bls);
     697             : 
     698             :     if (workaround_qpublic_key) {
     699          33 :         fqc.quorumSig = fqc.membersSig;
     700             :     }
     701             : 
     702          33 :     if (!fqc.Verify({m_dmnman, m_qsnapman, m_chainman, m_quorum_base_block_index}, true)) {
     703           0 :         logger.Batch("failed to verify final commitment");
     704           0 :         assert(false);
     705             :     }
     706             : 
     707          66 :     logger.Batch("final commitment: validMembers=%d, signers=%d, quorumPublicKey=%s", fqc.CountValidMembers(),
     708          33 :                  fqc.CountSigners(), fqc.quorumPublicKey.ToString());
     709             : 
     710          33 :     logger.Flush();
     711             : 
     712          33 :     return fqc;
     713          64 : }
     714             : 
     715        8948 : bool ActiveDKGSession::MaybeDecrypt(const CBLSIESMultiRecipientObjects<CBLSSecretKey>& obj, size_t idx,
     716             :                                     CBLSSecretKey& ret_obj, int version)
     717             : {
     718        8948 :     return m_mn_activeman.Decrypt(obj, idx, ret_obj, version);
     719             : }
     720             : } // namespace llmq

Generated by: LCOV version 1.16