16 #include "validation.h"
20 #include <unordered_set>
31 if (
db.
Exists(std::string(
"rs_upgraded"))) {
38 db.
Write(std::string(
"rs_upgraded"), (uint8_t)1);
45 LogPrintf(
"CRecoveredSigsDb::%s -- converting invalid rs_t keys\n", __func__);
49 auto start = std::make_tuple(std::string(
"rs_t"), (uint32_t)0, (uint8_t)0,
uint256());
52 CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT);
54 while (pcursor->Valid()) {
57 if (!pcursor->GetKey(k) || std::get<0>(k) !=
"rs_t") {
62 std::get<1>(k) =
htobe32(std::get<1>(k));
63 batch.
Write(k, (uint8_t)1);
73 LogPrintf(
"CRecoveredSigsDb::%s -- converted %d invalid rs_t keys\n", __func__, cnt);
80 LogPrintf(
"CRecoveredSigsDb::%s -- adding rs_vt keys with current time\n", __func__);
86 auto start = std::make_tuple(std::string(
"rs_v"), (uint8_t)0,
uint256());
89 CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT);
91 while (pcursor->Valid()) {
94 if (!pcursor->GetKey(k) || std::get<0>(k) !=
"rs_v") {
98 uint8_t llmqType = std::get<1>(k);
99 const uint256&
id = std::get<2>(k);
101 auto k2 = std::make_tuple(std::string(
"rs_vt"), (uint32_t)
htobe32(curTime), llmqType,
id);
102 batch.
Write(k2, (uint8_t)1);
112 LogPrintf(
"CRecoveredSigsDb::%s -- added %d rs_vt entries\n", __func__, cnt);
117 auto k = std::make_tuple(std::string(
"rs_r"), (uint8_t)llmqType,
id, msgHash);
123 auto cacheKey = std::make_pair(llmqType,
id);
133 auto k = std::make_tuple(std::string(
"rs_r"), (uint8_t)llmqType,
id);
151 auto k = std::make_tuple(std::string(
"rs_s"), signHash);
169 auto k = std::make_tuple(std::string(
"rs_h"), hash);
179 auto k = std::make_tuple(std::string(
"rs_r"), (uint8_t)llmqType,
id);
189 }
catch (std::exception&) {
196 auto k1 = std::make_tuple(std::string(
"rs_h"), hash);
197 std::pair<uint8_t, uint256> k2;
212 CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT);
218 auto k1 = std::make_tuple(std::string(
"rs_r"), recSig.
llmqType, recSig.
id);
219 auto k2 = std::make_tuple(std::string(
"rs_r"), recSig.
llmqType, recSig.
id, recSig.
msgHash);
220 batch.
Write(k1, recSig);
222 batch.
Write(k2, curTime);
225 auto k3 = std::make_tuple(std::string(
"rs_h"), recSig.
GetHash());
230 auto k4 = std::make_tuple(std::string(
"rs_s"), signHash);
231 batch.
Write(k4, (uint8_t)1);
234 auto k5 = std::make_tuple(std::string(
"rs_t"), (uint32_t)
htobe32(curTime), recSig.
llmqType, recSig.
id);
235 batch.
Write(k5, (uint8_t)1);
260 auto k1 = std::make_tuple(std::string(
"rs_r"), recSig.
llmqType, recSig.
id);
261 auto k2 = std::make_tuple(std::string(
"rs_r"), recSig.
llmqType, recSig.
id, recSig.
msgHash);
262 auto k3 = std::make_tuple(std::string(
"rs_h"), recSig.
GetHash());
263 auto k4 = std::make_tuple(std::string(
"rs_s"), signHash);
276 writeTimeDs >> writeTime;
277 auto k5 = std::make_tuple(std::string(
"rs_t"), (uint32_t)
htobe32(writeTime), recSig.
llmqType, recSig.
id);
293 CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT);
303 CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT);
312 auto start = std::make_tuple(std::string(
"rs_t"), (uint32_t)0, (uint8_t)0,
uint256());
314 pcursor->Seek(start);
316 std::vector<std::pair<Consensus::LLMQType, uint256>> toDelete;
317 std::vector<decltype(start)> toDelete2;
319 while (pcursor->Valid()) {
322 if (!pcursor->GetKey(k) || std::get<0>(k) !=
"rs_t") {
325 if (
be32toh(std::get<1>(k)) >= endTime) {
330 toDelete2.emplace_back(k);
336 if (toDelete.empty()) {
340 CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT);
343 for (
auto& e : toDelete) {
353 for (
auto& e : toDelete2) {
359 LogPrint(
BCLog::LLMQ,
"CRecoveredSigsDb::%d -- deleted %d entries\n", __func__, toDelete.size());
364 auto k = std::make_tuple(std::string(
"rs_v"), (uint8_t)llmqType,
id);
370 auto k = std::make_tuple(std::string(
"rs_v"), (uint8_t)llmqType,
id);
371 return db.
Read(k, msgHashRet);
376 auto k1 = std::make_tuple(std::string(
"rs_v"), (uint8_t)llmqType,
id);
377 auto k2 = std::make_tuple(std::string(
"rs_vt"), (uint32_t)
htobe32(
GetAdjustedTime()), (uint8_t)llmqType,
id);
379 CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT);
380 batch.
Write(k1, msgHash);
381 batch.
Write(k2, (uint8_t)1);
390 auto start = std::make_tuple(std::string(
"rs_vt"), (uint32_t)0, (uint8_t)0,
uint256());
392 pcursor->Seek(start);
394 CDBBatch batch(CLIENT_VERSION | ADDRV2_FORMAT);
396 while (pcursor->Valid()) {
399 if (!pcursor->GetKey(k) || std::get<0>(k) !=
"rs_vt") {
402 if (
be32toh(std::get<1>(k)) >= endTime) {
406 uint8_t llmqType = std::get<2>(k);
407 const uint256&
id = std::get<3>(k);
410 batch.
Erase(std::make_tuple(std::string(
"rs_v"), llmqType,
id));
457 vRecv >> recoveredSig;
479 LogPrint(
BCLog::LLMQ,
"CSigningManager::%s -- signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__,
511 size_t maxUniqueSessions,
512 std::unordered_map<
NodeId, std::list<CRecoveredSig>>& retSigShares,
522 llmq::utils::IterateNodesRandom(
pendingRecoveredSigs, [&]() {
return uniqueSignHashes.size() < maxUniqueSessions; }, [&](
NodeId nodeId, std::list<CRecoveredSig>& ns) {
526 auto& recSig = *ns.begin();
531 retSigShares[nodeId].emplace_back(recSig);
533 ns.erase(ns.begin());
534 return !ns.empty(); },
rnd);
536 if (retSigShares.empty()) {
541 for (
auto& p : retSigShares) {
545 for (
auto it = v.begin(); it != v.end();) {
550 if (!retQuorums.count(quorumKey)) {
554 recSig.quorumHash.ToString(), nodeId);
559 LogPrint(
BCLog::LLMQ,
"CSigningManager::%s -- quorum %s not active anymore, node=%d\n", __func__,
560 recSig.quorumHash.ToString(), nodeId);
565 retQuorums.emplace(quorumKey, quorum);
575 std::unordered_map<NodeId, std::list<CRecoveredSig>> recSigsByNode;
579 if (recSigsByNode.empty()) {
587 size_t verifyCount = 0;
588 for (
auto& p : recSigsByNode) {
592 for (
auto& recSig : v) {
594 if (!recSig.sig.Get().IsValid()) {
599 const auto& quorum = quorums.at(std::make_pair((
Consensus::LLMQType)recSig.llmqType, recSig.quorumHash));
609 LogPrint(
BCLog::LLMQ,
"CSigningManager::%s -- verified recovered sig(s). count=%d, vt=%d, nodes=%d\n", __func__, verifyCount, verifyTimer.
count(), recSigsByNode.size());
611 std::unordered_set<uint256, StaticSaltedHasher> processed;
612 for (
auto& p : recSigsByNode) {
618 LogPrintf(
"CSigningManager::%s -- invalid recSig from other node, banning peer=%d\n", __func__, nodeId);
623 for (
auto& recSig : v) {
624 if (!processed.emplace(recSig.GetHash()).second) {
628 const auto& quorum = quorums.at(std::make_pair((
Consensus::LLMQType)recSig.llmqType, recSig.quorumHash));
646 if (db.HasRecoveredSigForHash(recoveredSig.GetHash())) {
650 std::vector<CRecoveredSigsListener*> listeners;
653 listeners = recoveredSigsListeners;
657 LogPrint(
BCLog::LLMQ,
"CSigningManager::%s -- valid recSig. signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__,
658 signHash.ToString(), recoveredSig.id.ToString(), recoveredSig.msgHash.ToString(), nodeId);
660 if (db.HasRecoveredSigForId(llmqType, recoveredSig.id)) {
661 CRecoveredSig otherRecoveredSig;
662 if (db.GetRecoveredSigById(llmqType, recoveredSig.id, otherRecoveredSig)) {
664 if (signHash != otherSignHash) {
667 LogPrintf(
"CSigningManager::%s -- conflicting recoveredSig for signHash=%s, id=%s, msgHash=%s, otherSignHash=%s\n", __func__,
668 signHash.ToString(), recoveredSig.id.ToString(), recoveredSig.msgHash.ToString(), otherSignHash.ToString());
682 db.WriteRecoveredSig(recoveredSig);
688 pnode->PushInventory(inv);
691 for (
auto& l : listeners) {
692 l->HandleNewRecoveredSig(recoveredSig);
698 db.TruncateRecoveredSig(llmqType,
id);
701 void CSigningManager::Cleanup()
704 if (now - lastCleanupTime < 5000) {
708 int64_t maxAge = DEFAULT_MAX_RECOVERED_SIGS_AGE;
710 db.CleanupOldRecoveredSigs(maxAge);
711 db.CleanupOldVotes(maxAge);
719 recoveredSigsListeners.emplace_back(l);
725 auto itRem = std::remove(recoveredSigsListeners.begin(), recoveredSigsListeners.end(), l);
726 recoveredSigsListeners.erase(itRem, recoveredSigsListeners.end());
740 bool hasVoted = db.HasVotedOnId(llmqType,
id);
743 db.GetVoteForId(llmqType,
id, prevMsgHash);
744 if (msgHash != prevMsgHash) {
745 LogPrintf(
"CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting on conflicting msgHash=%s\n", __func__,
748 }
else if (allowReSign) {
749 LogPrint(
BCLog::LLMQ,
"CSigningManager::%s -- already voted for id=%s and msgHash=%s. Resigning!\n", __func__,
750 id.ToString(), prevMsgHash.
ToString());
752 LogPrint(
BCLog::LLMQ,
"CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting again.\n", __func__,
753 id.ToString(), prevMsgHash.
ToString());
758 if (db.HasRecoveredSigForId(llmqType,
id)) {
763 db.WriteVoteForId(llmqType,
id, msgHash);
772 CQuorumCPtr quorum = SelectQuorumForSigning(llmqType,
id);
774 LogPrint(
BCLog::LLMQ,
"CSigningManager::%s -- failed to select quorum. id=%s, msgHash=%s\n", __func__,
id.ToString(), msgHash.
ToString());
793 return db.HasRecoveredSig(llmqType,
id, msgHash);
798 return db.HasRecoveredSigForId(llmqType,
id);
801 bool CSigningManager::HasRecoveredSigForSession(
const uint256& signHash)
803 return db.HasRecoveredSigForSession(signHash);
808 if (!db.HasRecoveredSigForId(llmqType,
id)) {
813 if (!db.HasRecoveredSig(llmqType,
id, msgHash)) {
824 return db.HasVotedOnId(llmqType,
id);
829 return db.GetVoteForId(llmqType,
id, msgHashRet);
835 size_t poolSize = (size_t)llmqParams.signingActiveQuorumCount;
840 if (signHeight == -1) {
843 int startBlockHeight = signHeight - signOffset;
850 auto quorums =
quorumManager->ScanQuorums(llmqType, pindexStart, poolSize);
851 if (quorums.empty()) {
855 std::vector<std::pair<uint256, size_t>> scores;
856 scores.reserve(quorums.size());
857 for (
size_t i = 0; i < quorums.size(); i++) {
859 h << (uint8_t)llmqType;
860 h << quorums[i]->qc.quorumHash;
862 scores.emplace_back(h.GetHash(), i);
864 std::sort(scores.begin(), scores.end());
865 return quorums[scores.front().second];
870 auto quorum = SelectQuorumForSigning(llmqType,
id, signedAtHeight);
CActiveDeterministicMasternodeManager * activeMasternodeManager
const CChainParams & Params()
Return the currently selected parameters.
const uint256 GetProTx() const
std::set< SourceId > badSources
void PushMessage(const SourceId &sourceId, const MessageId &msgId, const uint256 &msgHash, const CBLSSignature &sig, const CBLSPublicKey &pubKey)
bool VerifyInsecure(const CBLSPublicKey &pubKey, const uint256 &hash) const
static const std::string TESTNET
The block chain is a tree shaped structure starting with the genesis block at the root,...
int Height() const
Return the maximal height in the chain.
const Consensus::Params & GetConsensus() const
void RemoveAskFor(const uint256 &invHash, int invType)
Batch of changes queued to be written to a CDBWrapper.
size_t SizeEstimate() const
void Write(const K &key, const V &value)
CDBIterator * NewIterator()
bool WriteBatch(CDBBatch &batch, bool fSync=false)
bool Read(const K &key, V &value) const
bool ReadDataStream(const K &key, CDataStream &ssValue) const
bool Write(const K &key, const V &value, bool fSync=false)
bool Exists(const K &key) const
A writer stream (for serialization) that computes a 256-bit hash.
Information about a peer.
std::atomic< int > nVersion
std::atomic< bool > m_wants_recsigs
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.
const uint256 & GetHash() const
void CleanupOldVotes(int64_t maxAge)
bool HasRecoveredSigForHash(const uint256 &hash)
bool HasRecoveredSig(Consensus::LLMQType llmqType, const uint256 &id, const uint256 &msgHash)
CRecoveredSigsDb(CDBWrapper &_db)
unordered_lru_cache< uint256, bool, StaticSaltedHasher, 30000 > hasSigForHashCache
bool GetVoteForId(Consensus::LLMQType llmqType, const uint256 &id, uint256 &msgHashRet)
unordered_lru_cache< std::pair< Consensus::LLMQType, uint256 >, bool, StaticSaltedHasher, 30000 > hasSigForIdCache
void TruncateRecoveredSig(Consensus::LLMQType llmqType, const uint256 &id)
bool ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256 &id, CRecoveredSig &ret)
void RemoveRecoveredSig(Consensus::LLMQType llmqType, const uint256 &id)
void WriteVoteForId(Consensus::LLMQType llmqType, const uint256 &id, const uint256 &msgHash)
void ConvertInvalidTimeKeys()
unordered_lru_cache< uint256, bool, StaticSaltedHasher, 30000 > hasSigForSessionCache
bool HasRecoveredSigForSession(const uint256 &signHash)
void CleanupOldRecoveredSigs(int64_t maxAge)
bool GetRecoveredSigById(Consensus::LLMQType llmqType, const uint256 &id, CRecoveredSig &ret)
void WriteRecoveredSig(const CRecoveredSig &recSig)
bool GetRecoveredSigByHash(const uint256 &hash, CRecoveredSig &ret)
bool HasVotedOnId(Consensus::LLMQType llmqType, const uint256 &id)
bool HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256 &id)
void ProcessMessage(CNode *pnode, const std::string &strCommand, CDataStream &vRecv, CConnman &connman)
void ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig &recoveredSig, const CQuorumCPtr &quorum, CConnman &connman)
bool AlreadyHave(const CInv &inv)
bool PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig &recoveredSig, bool &retBan)
bool GetRecoveredSigForGetData(const uint256 &hash, CRecoveredSig &ret)
bool ProcessPendingRecoveredSigs(CConnman &connman)
void ProcessMessageRecoveredSig(CNode *pfrom, const CRecoveredSig &recoveredSig, CConnman &connman)
std::unordered_map< NodeId, std::list< CRecoveredSig > > pendingRecoveredSigs
CSigningManager(CDBWrapper &llmqDb, bool fMemory)
void CollectPendingRecoveredSigsToVerify(size_t maxUniqueSessions, std::unordered_map< NodeId, std::list< CRecoveredSig >> &retSigShares, std::unordered_map< std::pair< Consensus::LLMQType, uint256 >, CQuorumCPtr, StaticSaltedHasher > &retQuorums)
bool get(const Key &key, Value &value)
void erase(const Key &key)
void insert(const Key &key, const Value &v)
uint32_t htobe32(uint32_t host_32bits)
uint32_t be32toh(uint32_t big_endian_32bits)
std::unique_ptr< CConnman > g_connman
#define LogPrint(category,...)
uint256 BuildSignHash(Consensus::LLMQType llmqType, const uint256 &quorumHash, const uint256 &id, const uint256 &msgHash)
bool IsQuorumActive(Consensus::LLMQType llmqType, const uint256 &quorumHash)
std::shared_ptr< const CQuorum > CQuorumCPtr
std::unique_ptr< CQuorumManager > quorumManager
std::unique_ptr< CSigningManager > quorumSigningManager
std::unique_ptr< CSigSharesManager > quorumSigSharesManager
void Misbehaving(NodeId pnode, int howmuch, const std::string &message) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Increase a node's misbehavior score.
RecursiveMutex cs_main
Global state.
@ MSG_QUORUM_RECOVERED_SIG
std::map< LLMQType, LLMQParams > llmqs
#define AssertLockHeld(cs)
int64_t GetAdjustedTime()
int64_t GetTimeMillis()
Returns the system time (not mockable)
CChain chainActive
The currently-connected chain of blocks (protected by cs_main).