Line data Source code
1 : // Copyright (c) 2018-2021 The Dash Core developers
2 : // Copyright (c) 2022 The PIVX Core developers
3 : // Distributed under the MIT/X11 software license, see the accompanying
4 : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 :
6 : #ifndef PIVX_LLMQ_QUORUMS_DKGSESSION_H
7 : #define PIVX_LLMQ_QUORUMS_DKGSESSION_H
8 :
9 : #include "bls/bls_ies.h"
10 : #include "bls/bls_worker.h"
11 : #include "consensus/params.h"
12 : #include "evo/deterministicmns.h"
13 : #include "net.h"
14 : #include "llmq/quorums_utils.h"
15 : #include "logging.h"
16 :
17 : class UniValue;
18 :
19 : namespace llmq
20 : {
21 :
22 : class CFinalCommitment;
23 : class CDKGSession;
24 : class CDKGSessionManager;
25 : class CDKGPendingMessages;
26 :
27 1501 : class CDKGLogger : public CBatchedLogger
28 : {
29 : public:
30 : CDKGLogger(const CDKGSession& _quorumDkg, const std::string& _func);
31 : CDKGLogger(const std::string& _llmqTypeName, const uint256& _quorumHash, int _height, bool _areWeMember, const std::string& _func);
32 : };
33 :
34 : class CDKGContribution
35 : {
36 : public:
37 : uint8_t llmqType;
38 : uint256 quorumHash;
39 : uint256 proTxHash;
40 : BLSVerificationVectorPtr vvec;
41 : std::shared_ptr<CBLSIESMultiRecipientObjects<CBLSSecretKey>> contributions;
42 : CBLSSignature sig;
43 :
44 : public:
45 : template<typename Stream>
46 629 : inline void SerializeWithoutSig(Stream& s) const
47 : {
48 629 : s << llmqType;
49 629 : s << quorumHash;
50 629 : s << proTxHash;
51 629 : s << *vvec;
52 629 : s << *contributions;
53 629 : }
54 : template<typename Stream>
55 375 : inline void Serialize(Stream& s) const
56 : {
57 375 : SerializeWithoutSig(s);
58 375 : s << sig;
59 : }
60 : template<typename Stream>
61 186 : inline void Unserialize(Stream& s)
62 : {
63 186 : BLSVerificationVector tmp1;
64 186 : CBLSIESMultiRecipientObjects<CBLSSecretKey> tmp2;
65 :
66 186 : s >> llmqType;
67 186 : s >> quorumHash;
68 186 : s >> proTxHash;
69 186 : s >> tmp1;
70 186 : s >> tmp2;
71 186 : s >> sig;
72 :
73 186 : vvec = std::make_shared<BLSVerificationVector>(std::move(tmp1));
74 186 : contributions = std::make_shared<CBLSIESMultiRecipientObjects<CBLSSecretKey>>(std::move(tmp2));
75 186 : }
76 :
77 254 : uint256 GetSignHash() const
78 : {
79 254 : CHashWriter hw(SER_GETHASH, 0);
80 254 : SerializeWithoutSig(hw);
81 508 : hw << CBLSSignature();
82 254 : return hw.GetHash();
83 : }
84 : };
85 :
86 253 : class CDKGComplaint
87 : {
88 : public:
89 : uint8_t llmqType;
90 : uint256 quorumHash;
91 : uint256 proTxHash;
92 : std::vector<bool> badMembers;
93 : std::vector<bool> complainForMembers;
94 : CBLSSignature sig;
95 :
96 : public:
97 316 : CDKGComplaint() {}
98 : explicit CDKGComplaint(const Consensus::LLMQParams& params);
99 :
100 382 : SERIALIZE_METHODS(CDKGComplaint, obj)
101 : {
102 204 : READWRITE(obj.llmqType);
103 204 : READWRITE(obj.quorumHash);
104 204 : READWRITE(obj.proTxHash);
105 204 : READWRITE(DYNBITSET(obj.badMembers));
106 204 : READWRITE(DYNBITSET(obj.complainForMembers));
107 204 : READWRITE(obj.sig);
108 204 : }
109 :
110 66 : uint256 GetSignHash() const
111 : {
112 66 : CDKGComplaint tmp(*this);
113 66 : tmp.sig = CBLSSignature();
114 132 : return ::SerializeHash(tmp);
115 : }
116 : };
117 :
118 53 : class CDKGJustification
119 : {
120 : public:
121 : uint8_t llmqType;
122 : uint256 quorumHash;
123 : uint256 proTxHash;
124 : std::vector<std::pair<uint32_t, CBLSSecretKey>> contributions;
125 : CBLSSignature sig;
126 :
127 : public:
128 :
129 96 : SERIALIZE_METHODS(CDKGJustification, obj)
130 : {
131 52 : READWRITE(obj.llmqType);
132 52 : READWRITE(obj.quorumHash);
133 52 : READWRITE(obj.proTxHash);
134 52 : READWRITE(obj.contributions);
135 52 : READWRITE(obj.sig);
136 52 : }
137 :
138 16 : uint256 GetSignHash() const
139 : {
140 16 : CDKGJustification tmp(*this);
141 16 : tmp.sig = CBLSSignature();
142 32 : return ::SerializeHash(tmp);
143 : }
144 : };
145 :
146 : // each member commits to a single set of valid members with this message
147 : // then each node aggregate all received premature commitments
148 : // into a single CFinalCommitment, which is only valid if
149 : // enough (>=minSize) premature commitments were aggregated
150 626 : class CDKGPrematureCommitment
151 : {
152 : public:
153 : uint8_t llmqType;
154 : uint256 quorumHash;
155 : uint256 proTxHash;
156 : std::vector<bool> validMembers;
157 :
158 : CBLSPublicKey quorumPublicKey;
159 : uint256 quorumVvecHash;
160 :
161 : CBLSSignature quorumSig; // threshold sig share of quorumHash+validMembers+pubKeyHash+vvecHash
162 : CBLSSignature sig; // single member sig of quorumHash+validMembers+pubKeyHash+vvecHash
163 :
164 : public:
165 1848 : CDKGPrematureCommitment() {}
166 : explicit CDKGPrematureCommitment(const Consensus::LLMQParams& params);
167 :
168 535 : int CountValidMembers() const
169 : {
170 535 : return (int)std::count(validMembers.begin(), validMembers.end(), true);
171 : }
172 :
173 : public:
174 :
175 798 : SERIALIZE_METHODS(CDKGPrematureCommitment, obj)
176 : {
177 479 : READWRITE(obj.llmqType);
178 479 : READWRITE(obj.quorumHash);
179 479 : READWRITE(obj.proTxHash);
180 479 : READWRITE(DYNBITSET(obj.validMembers));
181 479 : READWRITE(obj.quorumPublicKey);
182 479 : READWRITE(obj.quorumVvecHash);
183 479 : READWRITE(obj.quorumSig);
184 479 : READWRITE(obj.sig);
185 479 : }
186 :
187 360 : uint256 GetSignHash() const
188 : {
189 360 : return utils::BuildCommitmentHash((Consensus::LLMQType)llmqType, quorumHash, validMembers, quorumPublicKey, quorumVvecHash);
190 : }
191 : };
192 :
193 : class CDKGMember
194 : {
195 : public:
196 : CDKGMember(CDeterministicMNCPtr _dmn, size_t _idx);
197 :
198 : CDeterministicMNCPtr dmn;
199 : size_t idx;
200 : CBLSId id;
201 :
202 : std::set<uint256> contributions;
203 : std::set<uint256> complaints;
204 : std::set<uint256> justifications;
205 : std::set<uint256> prematureCommitments;
206 :
207 : std::set<uint256> badMemberVotes;
208 : std::set<uint256> complaintsFromOthers;
209 :
210 : bool bad{false};
211 : bool weComplain{false};
212 : bool someoneComplain{false};
213 : };
214 :
215 : /**
216 : * The DKG session is a single instance of the DKG process. It is owned and called by CDKGSessionHandler, which passes
217 : * received DKG messages to the session. The session is not persistent and will loose it's state (the whole object is
218 : * discarded) when it finishes (after the mining phase) or is aborted.
219 : *
220 : * When incoming contributions are received and the verification vector is valid, it is passed to CDKGSessionManager
221 : * which will store it in the evo DB. Secret key contributions which are meant for the local member are also passed
222 : * to CDKGSessionManager to store them in the evo DB. If verification of the SK contribution initially fails, it is
223 : * not passed to CDKGSessionManager. If the justification phase later gives a valid SK contribution from the same
224 : * member, it is then passed to CDKGSessionManager and after this handled the same way.
225 : *
226 : * The contributions stored by CDKGSessionManager are then later loaded by the quorum instances and used for signing
227 : * sessions, but only if the local node is a member of the quorum.
228 : */
229 : class CDKGSession
230 : {
231 : friend class CDKGSessionHandler;
232 : friend class CDKGSessionManager;
233 : friend class CDKGLogger;
234 : template<typename Message> friend class CDKGMessageHandler;
235 :
236 : private:
237 : const Consensus::LLMQParams& params;
238 :
239 : CBLSWorker& blsWorker;
240 : CBLSWorkerCache cache;
241 : CDKGSessionManager& dkgManager;
242 :
243 : const CBlockIndex* pindexQuorum;
244 :
245 : std::vector<std::unique_ptr<CDKGMember>> members;
246 : std::map<uint256, size_t> membersMap;
247 : std::set<uint256> relayMembers;
248 : BLSVerificationVectorPtr vvecContribution;
249 : BLSSecretKeyVector skContributions;
250 :
251 : BLSIdVector memberIds;
252 : std::vector<BLSVerificationVectorPtr> receivedVvecs;
253 : // these are not necessarily verified yet. Only trust in what was written to the DB
254 : BLSSecretKeyVector receivedSkContributions;
255 :
256 : uint256 myProTxHash;
257 : CBLSId myId;
258 : size_t myIdx{(size_t)-1};
259 :
260 : // all indexed by msg hash
261 : // we expect to only receive a single vvec and contribution per member, but we must also be able to relay
262 : // conflicting messages as otherwise an attacker might be able to broadcast conflicting (valid+invalid) messages
263 : // and thus split the quorum. Such members are later removed from the quorum.
264 : mutable RecursiveMutex invCs;
265 : std::map<uint256, CDKGContribution> contributions;
266 : std::map<uint256, CDKGComplaint> complaints;
267 : std::map<uint256, CDKGJustification> justifications;
268 : std::map<uint256, CDKGPrematureCommitment> prematureCommitments;
269 :
270 : std::set<uint256> seenMessages;
271 :
272 : std::vector<size_t> pendingContributionVerifications;
273 :
274 : // filled by ReceivePrematureCommitment and used by FinalizeCommitments
275 : std::set<uint256> validCommitments;
276 :
277 : public:
278 983 : CDKGSession(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker, CDKGSessionManager& _dkgManager) :
279 1966 : params(_params), blsWorker(_blsWorker), cache(_blsWorker), dkgManager(_dkgManager) {}
280 :
281 : bool Init(const CBlockIndex* _pindexQuorum, const std::vector<CDeterministicMNCPtr>& mns, const uint256& _myProTxHash);
282 :
283 0 : size_t GetMyMemberIndex() const { return myIdx; }
284 :
285 : /**
286 : * The following sets of methods are for the first 4 phases handled in the session. The flow of message calls
287 : * is identical for all phases:
288 : * 1. Execute local action (e.g. create/send own contributions)
289 : * 2. PreVerify incoming messages for this phase. Preverification means that everything from the message is checked
290 : * that does not require too much resources for verification. This specifically excludes all CPU intensive BLS
291 : * operations.
292 : * 3. CDKGSessionHandler will collect pre verified messages in batches and perform batched BLS signature verification
293 : * on these.
294 : * 4. ReceiveMessage is called for each pre verified message with a valid signature. ReceiveMessage is also
295 : * responsible for further verification of validity (e.g. validate vvecs and SK contributions).
296 : */
297 :
298 : // Phase 1: contribution
299 : void Contribute(CDKGPendingMessages& pendingMessages);
300 : void SendContributions(CDKGPendingMessages& pendingMessages);
301 : bool PreVerifyMessage(const CDKGContribution& qc, bool& retBan) const;
302 : void ReceiveMessage(const uint256& hash, const CDKGContribution& qc, bool& retBan);
303 : void VerifyPendingContributions();
304 :
305 : // Phase 2: complaint
306 : void VerifyAndComplain(CDKGPendingMessages& pendingMessages);
307 : void VerifyConnectionAndMinProtoVersions();
308 : void SendComplaint(CDKGPendingMessages& pendingMessages);
309 : bool PreVerifyMessage(const CDKGComplaint& qc, bool& retBan) const;
310 : void ReceiveMessage(const uint256& hash, const CDKGComplaint& qc, bool& retBan);
311 :
312 : // Phase 3: justification
313 : void VerifyAndJustify(CDKGPendingMessages& pendingMessages);
314 : void SendJustification(CDKGPendingMessages& pendingMessages, const std::set<uint256>& forMembers);
315 : bool PreVerifyMessage(const CDKGJustification& qj, bool& retBan) const;
316 : void ReceiveMessage(const uint256& hash, const CDKGJustification& qj, bool& retBan);
317 :
318 : // Phase 4: commit
319 : void VerifyAndCommit(CDKGPendingMessages& pendingMessages);
320 : void SendCommitment(CDKGPendingMessages& pendingMessages);
321 : bool PreVerifyMessage(const CDKGPrematureCommitment& qc, bool& retBan) const;
322 : void ReceiveMessage(const uint256& hash, const CDKGPrematureCommitment& qc, bool& retBan);
323 :
324 : // Phase 5: aggregate/finalize
325 : std::vector<CFinalCommitment> FinalizeCommitments();
326 :
327 10408 : bool AreWeMember() const { return !myProTxHash.IsNull(); }
328 : void MarkBadMember(CDKGMember* member);
329 :
330 : void RelayInvToParticipants(const CInv& inv) const;
331 :
332 : CDKGMember* GetMember(const uint256& proTxHash) const;
333 :
334 : private:
335 : bool ShouldSimulateError(const std::string& error_type);
336 : };
337 :
338 : // Return false if error_type is not found
339 : bool SetSimulatedDKGErrorRate(const std::string& error_type, double rate);
340 :
341 : }
342 :
343 : #endif // PIVX_LLMQ_QUORUMS_DKGSESSION_H
|