20 #include "validation.h"
26 static std::map<std::string, double> simDkgErrorMap = {
27 {
"contribution-omit", 0.0},
28 {
"contribution-lie", 0.0},
29 {
"complain-lie", 0.0},
31 {
"justify-omit", 0.0},
39 auto it = simDkgErrorMap.find(error_type);
40 if (it != simDkgErrorMap.end()) {
47 static double GetSimulatedErrorRate(
const std::string& error_type)
50 auto it = simDkgErrorMap.find(error_type);
51 if (it != simDkgErrorMap.end()) {
63 double rate = GetSimulatedErrorRate(error_type);
68 CDKGLogger(_quorumDkg.params.
name, _quorumDkg.pindexQuorum->GetBlockHash(), _quorumDkg.pindexQuorum->nHeight, _quorumDkg.AreWeMember(), _func)
79 badMembers((size_t)params.size), complainForMembers((size_t)params.size)
84 validMembers((size_t)params.size)
111 for (
size_t i = 0; i < mns.size(); i++) {
117 if (!_myProTxHash.
IsNull()) {
118 for (
size_t i = 0; i <
members.size(); i++) {
120 if (m->dmn->proTxHash == _myProTxHash) {
130 LogPrint(
BCLog::DKG,
"CDKGSession::%s: initialized as observer. mns=%d\n", __func__, mns.size());
134 LogPrint(
BCLog::DKG,
"CDKGSession::%s: initialized as member. mns=%d\n", __func__, mns.size());
149 logger.
Batch(
"generating contributions");
152 logger.
Batch(
"GenerateContributions failed");
155 logger.
Batch(
"generated contributions. time=%d", t1.
count());
166 logger.
Batch(
"sending contributions");
169 logger.
Batch(
"omitting");
180 qc.
contributions = std::make_shared<CBLSIESMultiRecipientObjects<CBLSSecretKey>>();
183 for (
size_t i = 0; i <
members.size(); i++) {
188 logger.
Batch(
"lying for %s", m->dmn->proTxHash.ToString());
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());
198 logger.
Batch(
"encrypted contributions. time=%d", t1.
count());
220 logger.
Batch(
"contribution for wrong quorum, rejecting");
226 logger.
Batch(
"contributor not a member of this quorum, rejecting contribution");
232 logger.
Batch(
"invalid contributions count");
237 logger.
Batch(
"invalid verification vector length");
243 logger.
Batch(
"invalid verification vector");
248 if (member->contributions.size() >= 2) {
252 logger.
Batch(
"dropping contribution from %s as we already got %d contributions", member->dmn->proTxHash.ToString(), member->contributions.size());
275 if (member->contributions.size() >= 2) {
281 member->contributions.emplace(hash);
287 status.receivedContribution = true;
291 if (member->contributions.size() > 1) {
295 logger.
Batch(
"%s did send multiple contributions", member->dmn->proTxHash.ToString());
302 int receivedCount = 0;
303 for (
const auto& m :
members) {
304 if (!m->contributions.empty()) {
309 logger.
Batch(
"received and relayed contribution. received=%d/%d, time=%d", receivedCount,
members.size(), t1.
count());
320 bool complain =
false;
323 logger.
Batch(
"contribution from %s could not be decrypted", member->dmn->proTxHash.ToString());
326 logger.
Batch(
"lying/complaining for %s", member->dmn->proTxHash.ToString());
331 member->weComplain =
true;
333 status.weComplain = true;
339 logger.
Batch(
"decrypted our contribution share. time=%d", t2.
count());
341 bool verifyPending =
false;
345 verifyPending =
true;
369 std::vector<size_t> memberIndexes;
370 std::vector<BLSVerificationVectorPtr> vvecs;
373 for (
const auto& idx : pend) {
375 if (m->bad || m->weComplain) {
378 memberIndexes.emplace_back(idx);
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());
389 for (
size_t i = 0; i < memberIndexes.size(); 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;
395 status.weComplain = true;
399 size_t memberIdx = memberIndexes[i];
404 logger.
Batch(
"verified %d pending contributions. time=%d", pend.size(), t1.
count());
426 for (
const auto& m :
members) {
430 if (m->contributions.empty()) {
431 logger.
Batch(
"%s did not send any contribution", m->dmn->proTxHash.ToString());
437 logger.
Batch(
"verified contributions. time=%d", t1.
count());
449 std::unordered_map<uint256, int, StaticSaltedHasher> protoMap;
462 auto it = protoMap.find(m->dmn->proTxHash);
463 if (it == protoMap.end()) {
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) {
468 logger.
Batch(
"%s does not have min proto version %d (has %d)", m->dmn->proTxHash.ToString(), MNAUTH_NODE_VER_VERSION, it->second);
474 logger.
Batch(
"%s no outbound connection since %d seconds", m->dmn->proTxHash.ToString(),
GetAdjustedTime() - lastOutbound);
491 int complaintCount = 0;
492 for (
size_t i = 0; i <
members.size(); i++) {
497 }
else if (m->weComplain) {
503 if (badCount == 0 && complaintCount == 0) {
507 logger.
Batch(
"sending complaint. badCount=%d, complaintCount=%d", badCount, complaintCount);
529 logger.
Batch(
"complaint for wrong quorum, rejecting");
535 logger.
Batch(
"complainer not a member of this quorum, rejecting complaint");
541 logger.
Batch(
"invalid badMembers bitset size");
547 logger.
Batch(
"invalid complainForMembers bitset size");
552 if (member->complaints.size() >= 2) {
556 logger.
Batch(
"dropping complaint from %s as we already got %d complaints",
557 member->dmn->proTxHash.ToString(), member->complaints.size());
577 if (member->complaints.size() >= 2) {
583 member->complaints.emplace(hash);
589 status.receivedComplaint = true;
593 if (member->complaints.size() > 1) {
597 logger.
Batch(
"%s did send multiple complaints", member->dmn->proTxHash.ToString());
602 int receivedCount = 0;
603 for (
size_t i = 0; i <
members.size(); i++) {
606 logger.
Batch(
"%s voted for %s to be bad", member->dmn->proTxHash.ToString(), m->dmn->proTxHash.ToString());
609 logger.
Batch(
"%s voted for us to be bad", member->dmn->proTxHash.ToString());
613 m->complaintsFromOthers.emplace(qc.
proTxHash);
614 m->someoneComplain =
true;
616 return status.complaintsFromMembers.emplace(member->idx).second;
619 logger.
Batch(
"%s complained about us", member->dmn->proTxHash.ToString());
622 if (!m->complaints.empty()) {
627 logger.
Batch(
"received and relayed complaint. received=%d", receivedCount);
638 std::set<uint256> justifyFor;
640 for (
const auto& m :
members) {
645 logger.
Batch(
"%s marked as bad as %d other members voted for this", m->dmn->proTxHash.ToString(), m->badMemberVotes.size());
649 if (m->complaints.empty()) {
652 if (m->complaints.size() != 1) {
653 logger.
Batch(
"%s sent multiple complaints", m->dmn->proTxHash.ToString());
658 auto& qc =
complaints.at(*m->complaints.begin());
659 if (qc.complainForMembers[
myIdx]) {
660 justifyFor.emplace(qc.proTxHash);
665 if (!justifyFor.empty()) {
676 logger.
Batch(
"sending justification for %d members", forMembers.size());
684 for (
size_t i = 0; i <
members.size(); i++) {
686 if (!forMembers.count(m->dmn->proTxHash)) {
689 logger.
Batch(
"justifying for %s", m->dmn->proTxHash.ToString());
694 logger.
Batch(
"lying for %s", m->dmn->proTxHash.ToString());
702 logger.
Batch(
"omitting");
726 logger.
Batch(
"justification for wrong quorum, rejecting");
732 logger.
Batch(
"justifier not a member of this quorum, rejecting justification");
738 logger.
Batch(
"justification with no contributions");
743 std::set<size_t> contributionsSet;
745 if (p.first >
members.size()) {
746 logger.
Batch(
"invalid contribution index");
751 if (!contributionsSet.emplace(p.first).second) {
752 logger.
Batch(
"duplicate contribution index");
757 auto& skShare = p.second;
758 if (!skShare.IsValid()) {
759 logger.
Batch(
"invalid contribution");
765 if (member->justifications.size() >= 2) {
769 logger.
Batch(
"dropping justification from %s as we already got %d justifications",
770 member->dmn->proTxHash.ToString(), member->justifications.size());
790 if (member->justifications.size() >= 2) {
796 member->justifications.emplace(hash);
803 status.receivedJustification = true;
807 if (member->justifications.size() > 1) {
810 logger.
Batch(
"%s did send multiple justifications", member->dmn->proTxHash.ToString());
823 auto& member2 =
members[p.first];
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());
837 std::list<std::future<bool>> futures;
839 auto& member2 =
members[p.first];
840 auto& skContribution = p.second;
845 auto resultIt = futures.begin();
847 auto& member2 =
members[p.first];
848 auto& skContribution = p.second;
850 bool result = (resultIt++)->get();
852 logger.
Batch(
" %s did send an invalid justification for %s", member->dmn->proTxHash.ToString(), member2->dmn->proTxHash.ToString());
855 logger.
Batch(
" %s justified for %s", member->dmn->proTxHash.ToString(), member2->dmn->proTxHash.ToString());
858 member->weComplain =
false;
862 member->complaintsFromOthers.erase(member2->dmn->proTxHash);
866 int receivedCount = 0;
867 int expectedCount = 0;
869 for (
const auto& m :
members) {
870 if (!m->justifications.empty()) {
874 if (m->someoneComplain) {
879 logger.
Batch(
"verified justification: received=%d/%d time=%d", receivedCount, expectedCount, t1.
count());
890 std::vector<size_t> badMembers;
891 std::vector<size_t> openComplaintMembers;
893 for (
const auto& m :
members) {
895 badMembers.emplace_back(m->idx);
898 if (!m->complaintsFromOthers.empty()) {
900 openComplaintMembers.emplace_back(m->idx);
904 if (!badMembers.empty() || !openComplaintMembers.empty()) {
905 logger.
Batch(
"verification result:");
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());
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());
931 logger.
Batch(
"sending commitment");
938 for (
size_t i = 0; i <
members.size(); i++) {
946 logger.
Batch(
"not enough valid members. not sending commitment");
951 logger.
Batch(
"omitting");
958 std::vector<uint16_t> memberIndexes;
959 std::vector<BLSVerificationVectorPtr> vvecs;
962 logger.
Batch(
"failed to get valid contributions");
967 if (vvec ==
nullptr) {
968 logger.
Batch(
"failed to build quorum verification vector");
976 logger.
Batch(
"failed to build own secret share");
990 logger.
Batch(
"lying on commitment. lieType=%d", lieType);
997 }
else if (lieType == 1) {
1004 (*commitmentHash.
begin())++;
1014 }
else if (lieType == 4) {
1023 logger.
Batch(
"built premature commitment. time1=%d, time2=%d, time3=%d, totalTime=%d",
1044 logger.
Batch(
"commitment for wrong quorum, rejecting");
1050 logger.
Batch(
"committer not a member of this quorum, rejecting premature commitment");
1056 logger.
Batch(
"invalid validMembers bitset size");
1067 logger.
Batch(
"invalid membersSig");
1072 logger.
Batch(
"invalid quorumSig");
1080 logger.
Batch(
"invalid validMembers bitset. bit %d should not be set", i);
1085 if (member->prematureCommitments.size() >= 2) {
1089 logger.
Batch(
"dropping commitment from %s as we already got %d commitments",
1090 member->dmn->proTxHash.ToString(), member->prematureCommitments.size());
1115 member->prematureCommitments.emplace(hash);
1118 std::vector<uint16_t> memberIndexes;
1119 std::vector<BLSVerificationVectorPtr> vvecs;
1126 if (quorumVvec ==
nullptr) {
1127 logger.
Batch(
"failed to build quorum verification vector. skipping full verification");
1137 logger.
Batch(
"calculated quorum public key does not match");
1142 logger.
Batch(
"calculated quorum vvec hash does not match");
1148 logger.
Batch(
"failed to calculate public key share");
1153 logger.
Batch(
"failed to verify quorumSig");
1165 status.receivedPrematureCommitment = true;
1169 int receivedCount = 0;
1170 for (
const auto& m :
members) {
1171 if (!m->prematureCommitments.empty()) {
1178 logger.
Batch(
"verified premature commitment. received=%d/%d, time=%d", receivedCount,
members.size(), t1.
count());
1191 std::vector<CBLSPublicKey> allkeys;
1192 for (
const auto& m :
members) {
1193 allkeys.emplace_back(m->dmn->pdmnState->pubKeyOperator.Get());
1196 typedef std::vector<bool> Key;
1197 std::map<Key, std::vector<CDKGPrematureCommitment>> commitmentsMap;
1200 auto& qc = p.second;
1208 auto it = commitmentsMap.find(qc.validMembers);
1209 if (it == commitmentsMap.end()) {
1210 it = commitmentsMap.emplace(qc.validMembers, std::vector<CDKGPrematureCommitment>()).first;
1213 it->second.emplace_back(qc);
1218 std::vector<CFinalCommitment> finalCommitments;
1219 for (
const auto& p : commitmentsMap) {
1220 auto& cvec = p.second;
1226 std::vector<CBLSId> signerIds;
1227 std::vector<CBLSSignature> thresholdSigs;
1229 auto& first = cvec[0];
1238 std::vector<CBLSSignature> aggSigs;
1239 std::vector<CBLSPublicKey> aggPks;
1240 aggSigs.reserve(cvec.size());
1241 aggPks.reserve(cvec.size());
1243 for (
size_t i = 0; i < cvec.size(); i++) {
1246 if (qc.quorumPublicKey != first.quorumPublicKey || qc.quorumVvecHash != first.quorumVvecHash) {
1247 logger.
Batch(
"quorumPublicKey or quorumVvecHash does not match, skipping");
1251 size_t signerIndex =
membersMap[qc.proTxHash];
1252 const auto& m =
members[signerIndex];
1254 fqc.
signers[signerIndex] =
true;
1255 aggSigs.emplace_back(qc.sig);
1256 aggPks.emplace_back(m->dmn->pdmnState->pubKeyOperator.Get());
1258 signerIds.emplace_back(m->id);
1259 thresholdSigs.emplace_back(qc.quorumSig);
1268 logger.
Batch(
"failed to recover quorum sig");
1275 logger.
Batch(
"failed to verify final commitment");
1280 finalCommitments.emplace_back(fqc);
1282 logger.
Batch(
"final commitment: validMembers=%d, signers=%d, quorumPublicKey=%s, time1=%d, time2=%d, time3=%d, total=%d",
1290 return finalCommitments;
1299 return members[it->second].get();
1319 pnode->PushInventory(inv);
CActiveDeterministicMasternodeManager * activeMasternodeManager
std::shared_ptr< BLSVerificationVector > BLSVerificationVectorPtr
std::vector< CBLSSecretKey > BLSSecretKeyVector
const CChainParams & Params()
Return the currently selected parameters.
const CBLSSecretKey * OperatorKey() const
CBLSPublicKey GetPublicKey() const
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)
CBLSPublicKey BuildPubKeyShare(const uint256 &cacheKey, const BLSVerificationVectorPtr &vvec, const CBLSId &id)
CBLSSecretKey AggregateSecretKeys(const uint256 &cacheKey, const BLSSecretKeyVector &skShares)
std::vector< bool > VerifyContributionShares(const CBLSId &forId, const std::vector< BLSVerificationVectorPtr > &vvecs, const BLSSecretKeyVector &skShares, bool parallel=true, bool aggregated=true)
bool VerifyVerificationVector(const BLSVerificationVector &vvec, size_t start=0, size_t count=0)
std::future< bool > AsyncVerifyContributionShare(const CBLSId &forId, const BLSVerificationVectorPtr &vvec, const CBLSSecretKey &skContribution)
bool GenerateContributions(int threshold, const BLSIdVector &ids, BLSVerificationVectorPtr &vvecRet, BLSSecretKeyVector &skShares)
void SetByteVector(const std::vector< uint8_t > &vecBytes)
std::vector< uint8_t > ToByteVector() const
void Batch(const std::string &fmt, const Args &... args)
The block chain is a tree shaped structure starting with the genesis block at the root,...
uint256 GetBlockHash() const
int nHeight
height of the entry in the chain. The genesis block has height 0
CChainParams defines various tweakable parameters of a given instance of the PIVX system.
Information about a peer.
std::atomic< int > nVersion
uint256 verifiedProRegTxHash
std::string ToString() const
This class works as a stopwatch.
void stop()
Stop/pause the timer.
duration_t::rep count() const
Return the elapsed time.
uint256 GetSignHash() const
std::vector< bool > badMembers
std::vector< bool > complainForMembers
std::shared_ptr< CBLSIESMultiRecipientObjects< CBLSSecretKey > > contributions
uint256 GetSignHash() const
BLSVerificationVectorPtr vvec
bool sentPrematureCommitment
std::vector< std::pair< uint32_t, CBLSSecretKey > > contributions
uint256 GetSignHash() const
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)
std::vector< bool > validMembers
uint256 GetSignHash() const
CBLSPublicKey quorumPublicKey
int CountValidMembers() const
CDKGPrematureCommitment()
The DKG session is a single instance of the DKG process.
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)
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
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 VerifyPendingContributions()
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 ¶ms) const
CBLSPublicKey quorumPublicKey
int CountValidMembers() const
std::vector< bool > validMembers
std::vector< bool > signers
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.
std::unique_ptr< CConnman > g_connman
BCLog::Logger *const g_logger
NOTE: the logger instances is leaked on exit.
#define LogPrint(category,...)
std::string EncodePublic(const CChainParams ¶ms, const CBLSPublicKey &pk)
uint256 BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256 &blockHash, const std::vector< bool > &validMembers, const CBLSPublicKey &pubKey, const uint256 &vvecHash)
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
@ MSG_QUORUM_PREMATURE_COMMITMENT
bool GetRandBool(double rate) noexcept
int GetRandInt(int nMax) noexcept
int64_t GetAdjustedTime()