Line data Source code
1 : // Copyright (c) 2018-2025 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 :
5 : #include <llmq/signing.h>
6 :
7 : #include <llmq/commitment.h>
8 : #include <llmq/params.h>
9 : #include <llmq/quorumsman.h>
10 : #include <llmq/signhash.h>
11 :
12 : #include <chainparams.h>
13 : #include <dbwrapper.h>
14 : #include <streams.h>
15 : #include <util/system.h>
16 :
17 : #include <algorithm>
18 : #include <ranges>
19 : #include <unordered_map>
20 : #include <unordered_set>
21 :
22 : namespace llmq
23 : {
24 9189 : CRecoveredSigsDb::CRecoveredSigsDb(const util::DbWrapperParams& db_params) :
25 3063 : db{util::MakeDbWrapper({db_params.path / "llmq" / "recsigdb", db_params.memory, db_params.wipe, /*cache_size=*/8 << 20})}
26 3063 : {
27 6126 : }
28 :
29 6126 : CRecoveredSigsDb::~CRecoveredSigsDb() = default;
30 :
31 11309 : bool CRecoveredSigsDb::HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) const
32 : {
33 11309 : auto k = std::make_tuple(std::string("rs_r"), llmqType, id, msgHash);
34 11309 : return db->Exists(k);
35 11309 : }
36 :
37 178405 : bool CRecoveredSigsDb::HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id) const
38 : {
39 178405 : auto cacheKey = std::make_pair(llmqType, id);
40 : bool ret;
41 : {
42 178405 : LOCK(cs_cache);
43 178405 : if (hasSigForIdCache.get(cacheKey, ret)) {
44 144538 : return ret;
45 : }
46 178405 : }
47 :
48 :
49 33867 : auto k = std::make_tuple(std::string("rs_r"), llmqType, id);
50 33867 : ret = db->Exists(k);
51 :
52 33867 : LOCK(cs_cache);
53 33867 : hasSigForIdCache.insert(cacheKey, ret);
54 33867 : return ret;
55 178405 : }
56 :
57 1639408 : bool CRecoveredSigsDb::HasRecoveredSigForSession(const uint256& signHash) const
58 : {
59 : bool ret;
60 : {
61 1639408 : LOCK(cs_cache);
62 1639408 : if (hasSigForSessionCache.get(signHash, ret)) {
63 1625013 : return ret;
64 : }
65 1639408 : }
66 :
67 14395 : auto k = std::make_tuple(std::string("rs_s"), signHash);
68 14395 : ret = db->Exists(k);
69 :
70 14395 : LOCK(cs_cache);
71 14395 : hasSigForSessionCache.insert(signHash, ret);
72 14395 : return ret;
73 1639408 : }
74 :
75 153604 : bool CRecoveredSigsDb::HasRecoveredSigForHash(const uint256& hash) const
76 : {
77 : bool ret;
78 : {
79 153604 : LOCK(cs_cache);
80 153604 : if (hasSigForHashCache.get(hash, ret)) {
81 126336 : return ret;
82 : }
83 153604 : }
84 :
85 27268 : auto k = std::make_tuple(std::string("rs_h"), hash);
86 27268 : ret = db->Exists(k);
87 :
88 27268 : LOCK(cs_cache);
89 27268 : hasSigForHashCache.insert(hash, ret);
90 27268 : return ret;
91 153604 : }
92 :
93 9440 : bool CRecoveredSigsDb::ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret) const
94 : {
95 9440 : auto k = std::make_tuple(std::string("rs_r"), llmqType, id);
96 :
97 9440 : CDataStream ds(SER_DISK, CLIENT_VERSION);
98 9440 : if (!db->ReadDataStream(k, ds)) {
99 2888 : return false;
100 : }
101 :
102 : try {
103 6552 : ret.Unserialize(ds);
104 6552 : return true;
105 0 : } catch (std::exception&) {
106 0 : return false;
107 0 : }
108 9440 : }
109 :
110 2691 : bool CRecoveredSigsDb::GetRecoveredSigByHash(const uint256& hash, CRecoveredSig& ret) const
111 : {
112 2691 : auto k1 = std::make_tuple(std::string("rs_h"), hash);
113 2691 : std::pair<Consensus::LLMQType, uint256> k2;
114 2691 : if (!db->Read(k1, k2)) {
115 0 : return false;
116 : }
117 :
118 2691 : return ReadRecoveredSig(k2.first, k2.second, ret);
119 2691 : }
120 :
121 137 : bool CRecoveredSigsDb::GetRecoveredSigById(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret) const
122 : {
123 137 : return ReadRecoveredSig(llmqType, id, ret);
124 : }
125 :
126 27218 : void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig)
127 : {
128 27218 : CDBBatch batch(*db);
129 :
130 27218 : uint32_t curTime = GetTime<std::chrono::seconds>().count();
131 :
132 : // we put these close to each other to leverage leveldb's key compaction
133 : // this way, the second key can be used for fast HasRecoveredSig checks while the first key stores the recSig
134 27218 : auto k1 = std::make_tuple(std::string("rs_r"), recSig.getLlmqType(), recSig.getId());
135 27218 : auto k2 = std::make_tuple(std::string("rs_r"), recSig.getLlmqType(), recSig.getId(), recSig.getMsgHash());
136 27218 : batch.Write(k1, recSig);
137 : // this key is also used to store the current time, so that we can easily get to the "rs_t" key when we have the id
138 27218 : batch.Write(k2, curTime);
139 :
140 : // store by object hash
141 27218 : auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash());
142 27218 : batch.Write(k3, std::make_pair(recSig.getLlmqType(), recSig.getId()));
143 :
144 : // store by signHash
145 27218 : auto signHash = recSig.buildSignHash();
146 27218 : auto k4 = std::make_tuple(std::string("rs_s"), signHash.Get());
147 27214 : batch.Write(k4, (uint8_t)1);
148 :
149 : // store by current time. Allows fast cleanup of old recSigs
150 27218 : auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t)htobe32_internal(curTime), recSig.getLlmqType(), recSig.getId());
151 27214 : batch.Write(k5, (uint8_t)1);
152 :
153 27218 : db->WriteBatch(batch);
154 :
155 : {
156 27218 : LOCK(cs_cache);
157 27214 : hasSigForIdCache.insert(std::make_pair(recSig.getLlmqType(), recSig.getId()), true);
158 27218 : hasSigForSessionCache.insert(signHash.Get(), true);
159 27218 : hasSigForHashCache.insert(recSig.GetHash(), true);
160 27222 : }
161 27260 : }
162 :
163 6612 : void CRecoveredSigsDb::RemoveRecoveredSig(CDBBatch& batch, Consensus::LLMQType llmqType, const uint256& id, bool deleteHashKey, bool deleteTimeKey)
164 : {
165 6612 : CRecoveredSig recSig;
166 6612 : if (!ReadRecoveredSig(llmqType, id, recSig)) {
167 2888 : return;
168 : }
169 :
170 3724 : auto signHash = recSig.buildSignHash();
171 :
172 3724 : auto k1 = std::make_tuple(std::string("rs_r"), recSig.getLlmqType(), recSig.getId());
173 3724 : auto k2 = std::make_tuple(std::string("rs_r"), recSig.getLlmqType(), recSig.getId(), recSig.getMsgHash());
174 3724 : auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash());
175 3724 : auto k4 = std::make_tuple(std::string("rs_s"), signHash.Get());
176 3724 : batch.Erase(k1);
177 3724 : batch.Erase(k2);
178 3724 : if (deleteHashKey) {
179 1579 : batch.Erase(k3);
180 1579 : batch.Erase(k4);
181 1579 : }
182 :
183 3724 : if (deleteTimeKey) {
184 0 : CDataStream writeTimeDs(SER_DISK, CLIENT_VERSION);
185 0 : if (db->ReadDataStream(k2, writeTimeDs)) {
186 : uint32_t writeTime;
187 0 : writeTimeDs >> writeTime;
188 0 : auto k5 = std::make_tuple(std::string("rs_t"), (uint32_t) htobe32_internal(writeTime), recSig.getLlmqType(), recSig.getId());
189 0 : batch.Erase(k5);
190 0 : }
191 0 : }
192 :
193 3724 : LOCK(cs_cache);
194 3724 : hasSigForIdCache.erase(std::make_pair(recSig.getLlmqType(), recSig.getId()));
195 3724 : if (deleteHashKey) {
196 1579 : hasSigForSessionCache.erase(signHash.Get());
197 1579 : hasSigForHashCache.erase(recSig.GetHash());
198 1579 : }
199 6612 : }
200 :
201 : // Remove the recovered sig itself and all keys required to get from id -> recSig
202 : // This will leave the byHash and signHash key in-place so that HasRecoveredSigForHash /
203 : // late-share filtering still returns true
204 5023 : void CRecoveredSigsDb::TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id)
205 : {
206 5023 : CDBBatch batch(*db);
207 5023 : RemoveRecoveredSig(batch, llmqType, id, false, false);
208 5023 : db->WriteBatch(batch);
209 5023 : }
210 :
211 17341 : void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge)
212 : {
213 17341 : std::unique_ptr<CDBIterator> pcursor(db->NewIterator());
214 :
215 17341 : auto start = std::make_tuple(std::string("rs_t"), (uint32_t)0, (Consensus::LLMQType)0, uint256());
216 17341 : uint32_t endTime = (uint32_t)(GetTime<std::chrono::seconds>().count() - maxAge);
217 17341 : pcursor->Seek(start);
218 :
219 17341 : std::vector<std::pair<Consensus::LLMQType, uint256>> toDelete;
220 17341 : std::vector<decltype(start)> toDelete2;
221 :
222 18930 : while (pcursor->Valid()) {
223 7545 : decltype(start) k;
224 :
225 7545 : if (!pcursor->GetKey(k) || std::get<0>(k) != "rs_t") {
226 112 : break;
227 : }
228 7433 : if (be32toh_internal(std::get<1>(k)) >= endTime) {
229 5844 : break;
230 : }
231 :
232 1589 : toDelete.emplace_back(std::get<2>(k), std::get<3>(k));
233 1589 : toDelete2.emplace_back(k);
234 :
235 1589 : pcursor->Next();
236 7545 : }
237 17341 : pcursor.reset();
238 :
239 17341 : if (toDelete.empty()) {
240 17314 : return;
241 : }
242 :
243 27 : CDBBatch batch(*db);
244 1616 : for (const auto& e : toDelete) {
245 1589 : RemoveRecoveredSig(batch, e.first, e.second, true, false);
246 :
247 1589 : if (batch.SizeEstimate() >= (1 << 24)) {
248 0 : db->WriteBatch(batch);
249 0 : batch.Clear();
250 0 : }
251 : }
252 :
253 1616 : for (const auto& e : toDelete2) {
254 1589 : batch.Erase(e);
255 : }
256 :
257 27 : db->WriteBatch(batch);
258 :
259 27 : LogPrint(BCLog::LLMQ, "CRecoveredSigsDb::%d -- deleted %d entries\n", __func__, toDelete.size());
260 17341 : }
261 :
262 19484 : bool CRecoveredSigsDb::HasVotedOnId(Consensus::LLMQType llmqType, const uint256& id) const
263 : {
264 19484 : auto k = std::make_tuple(std::string("rs_v"), llmqType, id);
265 19484 : return db->Exists(k);
266 19484 : }
267 :
268 6565 : bool CRecoveredSigsDb::GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet) const
269 : {
270 6565 : auto k = std::make_tuple(std::string("rs_v"), llmqType, id);
271 6565 : return db->Read(k, msgHashRet);
272 6565 : }
273 :
274 18322 : void CRecoveredSigsDb::WriteVoteForId(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash)
275 : {
276 18322 : auto k1 = std::make_tuple(std::string("rs_v"), llmqType, id);
277 18322 : auto k2 = std::make_tuple(std::string("rs_vt"), (uint32_t)htobe32_internal(GetTime<std::chrono::seconds>().count()), llmqType, id);
278 :
279 18322 : CDBBatch batch(*db);
280 18322 : batch.Write(k1, msgHash);
281 18322 : batch.Write(k2, (uint8_t)1);
282 :
283 18322 : db->WriteBatch(batch);
284 18322 : }
285 :
286 17341 : void CRecoveredSigsDb::CleanupOldVotes(int64_t maxAge)
287 : {
288 17341 : std::unique_ptr<CDBIterator> pcursor(db->NewIterator());
289 :
290 17341 : auto start = std::make_tuple(std::string("rs_vt"), (uint32_t)0, (Consensus::LLMQType)0, uint256());
291 17341 : uint32_t endTime = (uint32_t)(GetTime<std::chrono::seconds>().count() - maxAge);
292 17341 : pcursor->Seek(start);
293 :
294 17341 : CDBBatch batch(*db);
295 17341 : size_t cnt = 0;
296 18818 : while (pcursor->Valid()) {
297 6106 : decltype(start) k;
298 :
299 6106 : if (!pcursor->GetKey(k) || std::get<0>(k) != "rs_vt") {
300 0 : break;
301 : }
302 6106 : if (be32toh_internal(std::get<1>(k)) >= endTime) {
303 4629 : break;
304 : }
305 :
306 1477 : Consensus::LLMQType llmqType = std::get<2>(k);
307 1477 : const uint256& id = std::get<3>(k);
308 :
309 1477 : batch.Erase(k);
310 1477 : batch.Erase(std::make_tuple(std::string("rs_v"), llmqType, id));
311 :
312 1477 : cnt++;
313 :
314 1477 : pcursor->Next();
315 6106 : }
316 17341 : pcursor.reset();
317 :
318 17341 : if (cnt == 0) {
319 17316 : return;
320 : }
321 :
322 25 : db->WriteBatch(batch);
323 :
324 25 : LogPrint(BCLog::LLMQ, "CRecoveredSigsDb::%d -- deleted %d entries\n", __func__, cnt);
325 17341 : }
326 :
327 : //////////////////
328 :
329 9189 : CSigningManager::CSigningManager(const CQuorumManager& _qman, const util::DbWrapperParams& db_params,
330 : int64_t max_recsigs_age) :
331 3063 : db{db_params},
332 3063 : qman{_qman},
333 3063 : m_max_recsigs_age{max_recsigs_age}
334 3063 : {
335 6126 : }
336 :
337 6126 : CSigningManager::~CSigningManager() = default;
338 :
339 66254 : bool CSigningManager::AlreadyHave(const CInv& inv) const
340 : {
341 66254 : if (inv.type != MSG_QUORUM_RECOVERED_SIG) {
342 0 : return false;
343 : }
344 : {
345 66254 : LOCK(cs_pending);
346 66254 : if (pendingReconstructedRecoveredSigs.count(inv.hash)) {
347 7 : return true;
348 : }
349 66254 : }
350 :
351 66247 : return db.HasRecoveredSigForHash(inv.hash);
352 66254 : }
353 :
354 2691 : bool CSigningManager::GetRecoveredSigForGetData(const uint256& hash, CRecoveredSig& ret) const
355 : {
356 2691 : if (!db.GetRecoveredSigByHash(hash, ret)) {
357 0 : return false;
358 : }
359 2691 : if (!IsQuorumActive(ret.getLlmqType(), qman, ret.getQuorumHash())) {
360 : // we don't want to propagate sigs from inactive quorums
361 0 : return false;
362 : }
363 2691 : return true;
364 2691 : }
365 :
366 33556 : void CSigningManager::VerifyAndProcessRecoveredSig(NodeId from, std::shared_ptr<CRecoveredSig> recoveredSig)
367 : {
368 33556 : auto llmq_type = recoveredSig->getLlmqType();
369 33556 : auto quorum = qman.GetQuorum(llmq_type, recoveredSig->getQuorumHash());
370 :
371 33556 : if (!quorum) {
372 0 : LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not found\n", __func__,
373 : recoveredSig->getQuorumHash().ToString());
374 0 : return;
375 : }
376 33556 : if (!IsQuorumActive(llmq_type, qman, quorum->qc->quorumHash)) {
377 0 : return;
378 : }
379 :
380 : // It's important to only skip seen *valid* sig shares here. See comment for CBatchedSigShare
381 : // We don't receive recovered sigs in batches, but we do batched verification per node on these
382 33556 : if (db.HasRecoveredSigForHash(recoveredSig->GetHash())) {
383 7245 : return;
384 : }
385 :
386 26311 : LogPrint(BCLog::LLMQ, "CSigningManager::%s -- signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__,
387 : recoveredSig->buildSignHash().ToString(), recoveredSig->getId().ToString(), recoveredSig->getMsgHash().ToString(), from);
388 :
389 26311 : LOCK(cs_pending);
390 26311 : if (pendingReconstructedRecoveredSigs.count(recoveredSig->GetHash())) {
391 : // no need to perform full verification
392 0 : LogPrint(BCLog::LLMQ, "CSigningManager::%s -- already pending reconstructed sig, signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__,
393 : recoveredSig->buildSignHash().ToString(), recoveredSig->getId().ToString(), recoveredSig->getMsgHash().ToString(), from);
394 0 : return;
395 : }
396 :
397 26311 : pendingRecoveredSigs[from].emplace_back(std::move(recoveredSig));
398 33556 : }
399 :
400 378122 : bool CSigningManager::CollectPendingRecoveredSigsToVerify(
401 : size_t maxUniqueSessions, std::unordered_map<NodeId, std::list<std::shared_ptr<const CRecoveredSig>>>& retSigShares,
402 : std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CBLSPublicKey, StaticSaltedHasher>& ret_pubkeys)
403 : {
404 378122 : bool more_work{false};
405 :
406 : {
407 378122 : LOCK(cs_pending);
408 378122 : if (pendingRecoveredSigs.empty()) {
409 272479 : return false;
410 : }
411 :
412 : // TODO: refactor it to remove duplicated code with `CSigSharesManager::CollectPendingSigSharesToVerify`
413 105643 : std::unordered_set<std::pair<NodeId, uint256>, StaticSaltedHasher> uniqueSignHashes;
414 666151 : IterateNodesRandom(pendingRecoveredSigs, [&]() {
415 454865 : return uniqueSignHashes.size() < maxUniqueSessions;
416 560502 : }, [&](NodeId nodeId, std::list<std::shared_ptr<const CRecoveredSig>>& ns) {
417 454859 : if (ns.empty()) {
418 428616 : return false;
419 : }
420 26243 : auto& recSig = *ns.begin();
421 :
422 26243 : bool alreadyHave = db.HasRecoveredSigForHash(recSig->GetHash());
423 26243 : if (!alreadyHave) {
424 22431 : uniqueSignHashes.emplace(nodeId, recSig->buildSignHash().Get());
425 22431 : retSigShares[nodeId].emplace_back(recSig);
426 22431 : }
427 26243 : ns.erase(ns.begin());
428 26243 : return !ns.empty();
429 560502 : }, rnd);
430 :
431 105643 : if (retSigShares.empty()) {
432 93395 : return false;
433 : }
434 :
435 24496 : more_work = std::any_of(pendingRecoveredSigs.begin(), pendingRecoveredSigs.end(),
436 76920 : [](const auto& p) { return !p.second.empty(); }) ||
437 12242 : !pendingReconstructedRecoveredSigs.empty();
438 378122 : }
439 :
440 51886 : for (auto& [nodeId, v] : retSigShares) {
441 39638 : for (auto it = v.begin(); it != v.end();) {
442 22431 : const auto& recSig = *it;
443 :
444 22431 : auto llmqType = recSig->getLlmqType();
445 22431 : auto quorumKey = std::make_pair(recSig->getLlmqType(), recSig->getQuorumHash());
446 22431 : if (!ret_pubkeys.count(quorumKey)) {
447 14027 : auto quorum = qman.GetQuorum(llmqType, recSig->getQuorumHash());
448 14027 : if (!quorum) {
449 0 : LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not found, node=%d\n", __func__,
450 : recSig->getQuorumHash().ToString(), nodeId);
451 0 : it = v.erase(it);
452 0 : continue;
453 : }
454 14027 : if (!IsQuorumActive(llmqType, qman, quorum->qc->quorumHash)) {
455 0 : LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not active anymore, node=%d\n", __func__,
456 : recSig->getQuorumHash().ToString(), nodeId);
457 0 : it = v.erase(it);
458 0 : continue;
459 : }
460 :
461 14027 : ret_pubkeys.emplace(quorumKey, quorum->qc->quorumPublicKey);
462 14027 : }
463 :
464 22431 : ++it;
465 : }
466 : }
467 :
468 12248 : return more_work;
469 378122 : }
470 :
471 378122 : Uint256HashMap<std::shared_ptr<const CRecoveredSig>> CSigningManager::FetchPendingReconstructed()
472 : {
473 378122 : Uint256HashMap<std::shared_ptr<const CRecoveredSig>> tmp;
474 756244 : WITH_LOCK(cs_pending, swap(tmp, pendingReconstructedRecoveredSigs));
475 378122 : return tmp;
476 378122 : }
477 :
478 : // signature must be verified already
479 27558 : bool CSigningManager::ProcessRecoveredSig(const std::shared_ptr<const CRecoveredSig>& recoveredSig)
480 : {
481 27558 : auto llmqType = recoveredSig->getLlmqType();
482 :
483 27558 : if (db.HasRecoveredSigForHash(recoveredSig->GetHash())) {
484 309 : return false;
485 : }
486 :
487 27249 : auto signHash = recoveredSig->buildSignHash();
488 :
489 27249 : LogPrint(BCLog::LLMQ, "CSigningManager::%s -- valid recSig. signHash=%s, id=%s, msgHash=%s\n", __func__,
490 : signHash.ToString(), recoveredSig->getId().ToString(), recoveredSig->getMsgHash().ToString());
491 :
492 27249 : if (db.HasRecoveredSigForId(llmqType, recoveredSig->getId())) {
493 31 : CRecoveredSig otherRecoveredSig;
494 31 : if (db.GetRecoveredSigById(llmqType, recoveredSig->getId(), otherRecoveredSig)) {
495 31 : auto otherSignHash = otherRecoveredSig.buildSignHash();
496 31 : if (signHash.Get() != otherSignHash.Get()) {
497 : // this should really not happen, as each masternode is participating in only one vote,
498 : // even if it's a member of multiple quorums. so a majority is only possible on one quorum and one msgHash per id
499 12 : LogPrintf("CSigningManager::%s -- conflicting recoveredSig for signHash=%s, id=%s, msgHash=%s, otherSignHash=%s\n", __func__,
500 : signHash.ToString(), recoveredSig->getId().ToString(), recoveredSig->getMsgHash().ToString(), otherSignHash.ToString());
501 12 : } else {
502 : // Looks like we're trying to process a recSig that is already known. This might happen if the same
503 : // recSig comes in through regular QRECSIG messages and at the same time through some other message
504 : // which allowed to reconstruct a recSig (e.g. ISLOCK). In this case, just bail out.
505 : }
506 31 : return false;
507 : } else {
508 : // This case is very unlikely. It can only happen when cleanup caused this specific recSig to vanish
509 : // between the HasRecoveredSigForId and GetRecoveredSigById call. If that happens, treat it as if we
510 : // never had that recSig
511 : }
512 31 : }
513 :
514 27218 : db.WriteRecoveredSig(*recoveredSig);
515 54436 : WITH_LOCK(cs_pending, pendingReconstructedRecoveredSigs.erase(recoveredSig->GetHash()));
516 :
517 27218 : return true;
518 27558 : }
519 :
520 27218 : std::vector<CRecoveredSigsListener*> CSigningManager::GetListeners() const
521 : {
522 27218 : LOCK(cs_listeners);
523 27218 : return recoveredSigsListeners;
524 27218 : }
525 :
526 281 : void CSigningManager::PushReconstructedRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig>& recoveredSig)
527 : {
528 281 : LOCK(cs_pending);
529 281 : pendingReconstructedRecoveredSigs.emplace(std::piecewise_construct, std::forward_as_tuple(recoveredSig->GetHash()), std::forward_as_tuple(recoveredSig));
530 281 : }
531 :
532 5023 : void CSigningManager::TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256& id)
533 : {
534 5023 : db.TruncateRecoveredSig(llmqType, id);
535 5023 : }
536 :
537 17341 : void CSigningManager::Cleanup()
538 : {
539 17341 : db.CleanupOldRecoveredSigs(m_max_recsigs_age);
540 17341 : db.CleanupOldVotes(m_max_recsigs_age);
541 17341 : }
542 :
543 2640 : void CSigningManager::RegisterRecoveredSigsListener(CRecoveredSigsListener* l)
544 : {
545 2640 : LOCK(cs_listeners);
546 2640 : recoveredSigsListeners.emplace_back(l);
547 2640 : }
548 :
549 2640 : void CSigningManager::UnregisterRecoveredSigsListener(CRecoveredSigsListener* l)
550 : {
551 2640 : LOCK(cs_listeners);
552 2640 : auto itRem = std::remove(recoveredSigsListeners.begin(), recoveredSigsListeners.end(), l);
553 2640 : recoveredSigsListeners.erase(itRem, recoveredSigsListeners.end());
554 2640 : }
555 :
556 9873 : bool CSigningManager::HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) const
557 : {
558 9873 : return db.HasRecoveredSig(llmqType, id, msgHash);
559 : }
560 :
561 123007 : bool CSigningManager::HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id) const
562 : {
563 123007 : return db.HasRecoveredSigForId(llmqType, id);
564 : }
565 :
566 1639408 : bool CSigningManager::HasRecoveredSigForSession(const uint256& signHash) const
567 : {
568 1639408 : return db.HasRecoveredSigForSession(signHash);
569 : }
570 :
571 106 : bool CSigningManager::GetRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id, llmq::CRecoveredSig& retRecSig) const
572 : {
573 106 : if (!db.GetRecoveredSigById(llmqType, id, retRecSig)) {
574 0 : return false;
575 : }
576 106 : return true;
577 106 : }
578 :
579 9688 : bool CSigningManager::IsConflicting(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) const
580 : {
581 9688 : if (!db.HasRecoveredSigForId(llmqType, id)) {
582 : // no recovered sig present, so no conflict
583 8252 : return false;
584 : }
585 :
586 1436 : if (!db.HasRecoveredSig(llmqType, id, msgHash)) {
587 : // recovered sig is present, but not for the given msgHash. That's a conflict!
588 703 : return true;
589 : }
590 :
591 : // all good
592 733 : return false;
593 9688 : }
594 :
595 5436 : bool CSigningManager::GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet) const
596 : {
597 5436 : return db.GetVoteForId(llmqType, id, msgHashRet);
598 : }
599 :
600 283724 : SignHash CSigBase::buildSignHash() const { return SignHash(llmqType, quorumHash, id, msgHash); }
601 :
602 :
603 78963 : bool IsQuorumActive(Consensus::LLMQType llmqType, const CQuorumManager& qman, const uint256& quorumHash)
604 : {
605 : // sig shares and recovered sigs are only accepted from recent/active quorums
606 : // we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could
607 : // fail while we are on the brink of a new quorum
608 78963 : const auto& llmq_params_opt = Params().GetLLMQ(llmqType);
609 78963 : assert(llmq_params_opt.has_value());
610 78963 : auto quorums = qman.ScanQuorums(llmqType, llmq_params_opt->keepOldConnections);
611 203684 : return std::ranges::any_of(quorums, [&quorumHash](const auto& q) { return q->qc->quorumHash == quorumHash; });
612 78963 : }
613 :
614 : } // namespace llmq
|