diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index f742e1e3570f2..d980caac60ce7 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -6,6 +6,7 @@ #include "quorums.h" #include "activemasternode.h" +#include "chain.h" #include "chainparams.h" #include "cxxtimer.h" #include "evo/deterministicmns.h" @@ -33,7 +34,7 @@ static uint256 MakeQuorumKey(const CQuorum& q) { CHashWriter hw(SER_NETWORK, 0); hw << (uint8_t)q.params.type; - hw << q.pindexQuorum->GetBlockHash(); + hw << q.qc.quorumHash; for (const auto& dmn : q.members) { hw << dmn->proTxHash; } @@ -51,13 +52,13 @@ CQuorum::~CQuorum() } } -void CQuorum::Init(const uint256& _minedBlockHash, const CBlockIndex* _pindexQuorum, const std::vector& _members, const std::vector& _validMembers, const CBLSPublicKey& _quorumPublicKey) +void CQuorum::Init(const CFinalCommitment& _qc, const CBlockIndex* _pindexQuorum, int _height, const uint256& _minedBlockHash, const std::vector& _members) { - minedBlockHash = _minedBlockHash; + qc = _qc; + height = _height; pindexQuorum = _pindexQuorum; members = _members; - validMembers = _validMembers; - quorumPublicKey = _quorumPublicKey; + minedBlockHash = _minedBlockHash; } bool CQuorum::IsMember(const uint256& proTxHash) const @@ -74,7 +75,7 @@ bool CQuorum::IsValidMember(const uint256& proTxHash) const { for (size_t i = 0; i < members.size(); i++) { if (members[i]->proTxHash == proTxHash) { - return validMembers[i]; + return qc.validMembers[i]; } } return false; @@ -82,7 +83,7 @@ bool CQuorum::IsValidMember(const uint256& proTxHash) const CBLSPublicKey CQuorum::GetPubKeyShare(size_t memberIdx) const { - if (quorumVvec == nullptr || memberIdx >= members.size() || !validMembers[memberIdx]) { + if (quorumVvec == nullptr || memberIdx >= members.size() || !qc.validMembers[memberIdx]) { return CBLSPublicKey(); } auto& m = members[memberIdx]; @@ -141,17 +142,17 @@ void CQuorum::StartCachePopulatorThread(std::shared_ptr _this) } cxxtimer::Timer t(true); - LogPrintf("CQuorum::StartCachePopulatorThread -- start\n"); + LogPrint(BCLog::LLMQ, "CQuorum::StartCachePopulatorThread -- start\n"); // this thread will exit after some time // when then later some other thread tries to get keys, it will be much faster _this->cachePopulatorThread = std::thread(&TraceThread >, "quorum-cachepop", [_this, t] { for (size_t i = 0; i < _this->members.size() && !_this->stopCachePopulatorThread && !ShutdownRequested(); i++) { - if (_this->validMembers[i]) { + if (_this->qc.validMembers[i]) { _this->GetPubKeyShare(i); } } - LogPrintf("CQuorum::StartCachePopulatorThread -- done. time=%d\n", t.count()); + LogPrint(BCLog::LLMQ, "CQuorum::StartCachePopulatorThread -- done. time=%d\n", t.count()); }); } @@ -178,14 +179,13 @@ void CQuorumManager::UpdatedBlockTip(const CBlockIndex* pindexNew, bool fInitial } } - bool CQuorumManager::BuildQuorumFromCommitment(const CFinalCommitment& qc, const CBlockIndex* pindexQuorum, const uint256& minedBlockHash, std::shared_ptr& quorum) const { assert(pindexQuorum); assert(qc.quorumHash == pindexQuorum->GetBlockHash()); auto members = deterministicMNManager->GetAllQuorumMembers((Consensus::LLMQType)qc.llmqType, pindexQuorum); - quorum->Init(minedBlockHash, pindexQuorum, members, qc.validMembers, qc.quorumPublicKey); + quorum->Init(qc, pindexQuorum, pindexQuorum->nHeight, minedBlockHash, members); bool hasValidVvec = false; if (quorum->ReadContributions(evoDb)) { @@ -195,7 +195,7 @@ bool CQuorumManager::BuildQuorumFromCommitment(const CFinalCommitment& qc, const quorum->WriteContributions(evoDb); hasValidVvec = true; } else { - LogPrintf("CQuorumManager::%s -- quorum.ReadContributions and BuildQuorumContributions for block %s failed\n", __func__, qc.quorumHash.ToString()); + LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- quorum.ReadContributions and BuildQuorumContributions for block %s failed\n", __func__, qc.quorumHash.ToString()); } } @@ -224,20 +224,20 @@ bool CQuorumManager::BuildQuorumContributions(const CFinalCommitment& fqc, std:: cxxtimer::Timer t2(true); quorumVvec = blsWorker.BuildQuorumVerificationVector(vvecs); if (quorumVvec == nullptr) { - LogPrintf("CQuorumManager::%s -- failed to build quorumVvec\n", __func__); + LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- failed to build quorumVvec\n", __func__); // without the quorum vvec, there can't be a skShare, so we fail here. Failure is not fatal here, as it still // allows to use the quorum as a non-member (verification through the quorum pub key) return false; } skShare = blsWorker.AggregateSecretKeys(skContributions); if (!skShare.IsValid()) { - LogPrintf("CQuorumManager::%s -- failed to build skShare\n", __func__); + LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- failed to build skShare\n", __func__); // We don't bail out here as this is not a fatal error and still allows us to recover public key shares (as we // have a valid quorum vvec at this point) } t2.stop(); - LogPrintf("CQuorumManager::%s -- built quorum vvec and skShare. time=%d\n", __func__, t2.count()); + LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- built quorum vvec and skShare. time=%d\n", __func__, t2.count()); quorum->quorumVvec = quorumVvec; quorum->skShare = skShare; diff --git a/src/llmq/quorums.h b/src/llmq/quorums.h index e31d01f4efb51..95a1534a89299 100644 --- a/src/llmq/quorums.h +++ b/src/llmq/quorums.h @@ -6,6 +6,7 @@ #ifndef PIVX_LLMQ_QUORUMS_H #define PIVX_LLMQ_QUORUMS_H +#include "llmq/quorums_commitment.h" #include "bls/bls_worker.h" #include "bls/bls_wrapper.h" #include "consensus/params.h" @@ -35,11 +36,11 @@ class CQuorum public: const Consensus::LLMQParams& params; - uint256 minedBlockHash; const CBlockIndex* pindexQuorum; + CFinalCommitment qc; + int height; + uint256 minedBlockHash; std::vector members; - std::vector validMembers; - CBLSPublicKey quorumPublicKey; // These are only valid when we either participated in the DKG or fully watched it BLSVerificationVectorPtr quorumVvec; @@ -55,7 +56,7 @@ class CQuorum public: CQuorum(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker) : params(_params), blsCache(_blsWorker), stopCachePopulatorThread(false) {} ~CQuorum(); - void Init(const uint256& minedBlockHash, const CBlockIndex* pindexQuorum, const std::vector& members, const std::vector& validMembers, const CBLSPublicKey& quorumPublicKey); + void Init(const CFinalCommitment& _qc, const CBlockIndex* pindexQuorum, int _height, const uint256& _minedBlockHash, const std::vector& _members); bool IsMember(const uint256& proTxHash) const; bool IsValidMember(const uint256& proTxHash) const; diff --git a/src/llmq/quorums_chainlocks.cpp b/src/llmq/quorums_chainlocks.cpp index d06a083565ba6..cd98c92fb7a5a 100644 --- a/src/llmq/quorums_chainlocks.cpp +++ b/src/llmq/quorums_chainlocks.cpp @@ -39,6 +39,12 @@ CChainLocksHandler::~CChainLocksHandler() void CChainLocksHandler::Start() { quorumSigningManager->RegisterRecoveredSigsListener(this); + scheduler->scheduleEvery([&]() { + EnforceBestChainLock(); + // regularely retry signing the current chaintip + TrySignChainTip(); + }, + 5000); } void CChainLocksHandler::Stop() @@ -106,7 +112,7 @@ void CChainLocksHandler::ProcessNewChainLock(NodeId from, const llmq::CChainLock LogPrintf("CChainLocksHandler::%s -- invalid CLSIG (%s), peer=%d\n", __func__, clsig.ToString(), from); if (from != -1) { LOCK(cs_main); - Misbehaving(from, 100); + Misbehaving(from, 10); } return; } @@ -147,88 +153,113 @@ void CChainLocksHandler::ProcessNewChainLock(NodeId from, const llmq::CChainLock bestChainLockBlockIndex = pindex; } - EnforceBestChainLock(); + scheduler->scheduleFromNow([&]() { + EnforceBestChainLock(); + }, + 0); - LogPrintf("CChainLocksHandler::%s -- processed new CLSIG (%s), peer=%d\n", - __func__, clsig.ToString(), from); + LogPrint(BCLog::LLMQ, "CChainLocksHandler::%s -- processed new CLSIG (%s), peer=%d\n", + __func__, clsig.ToString(), from); } void CChainLocksHandler::AcceptedBlockHeader(const CBlockIndex* pindexNew) { - bool doEnforce = false; - { - LOCK2(cs_main, cs); - - if (pindexNew->GetBlockHash() == bestChainLock.blockHash) { - LogPrintf("CChainLocksHandler::%s -- block header %s came in late, updating and enforcing\n", __func__, pindexNew->GetBlockHash().ToString()); + LOCK2(cs_main, cs); - if (bestChainLock.nHeight != pindexNew->nHeight) { - // Should not happen, same as the conflict check from ProcessNewChainLock. - LogPrintf("CChainLocksHandler::%s -- height of CLSIG (%s) does not match the specified block's height (%d)\n", - __func__, bestChainLock.ToString(), pindexNew->nHeight); - return; - } + if (pindexNew->GetBlockHash() == bestChainLock.blockHash) { + LogPrintf("CChainLocksHandler::%s -- block header %s came in late, updating and enforcing\n", __func__, pindexNew->GetBlockHash().ToString()); - bestChainLockBlockIndex = pindexNew; - doEnforce = true; + if (bestChainLock.nHeight != pindexNew->nHeight) { + // Should not happen, same as the conflict check from ProcessNewChainLock. + LogPrintf("CChainLocksHandler::%s -- height of CLSIG (%s) does not match the specified block's height (%d)\n", + __func__, bestChainLock.ToString(), pindexNew->nHeight); + return; } - } - if (doEnforce) { - EnforceBestChainLock(); + + // when EnforceBestChainLock is called later, it might end up invalidating other chains but not activating the + // CLSIG locked chain. This happens when only the header is known but the block is still missing yet. The usual + // block processing logic will handle this when the block arrives + bestChainLockWithKnownBlock = bestChainLock; + bestChainLockBlockIndex = pindexNew; } } void CChainLocksHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork) { + // don't call TrySignChainTip directly but instead let the scheduler call it. This way we ensure that cs_main is + // never locked and TrySignChainTip is not called twice in parallel. Also avoids recursive calls due to + // EnforceBestChainLock switching chains. + LOCK(cs); + if (tryLockChainTipScheduled) { + return; + } + tryLockChainTipScheduled = true; + scheduler->scheduleFromNow([&]() { + EnforceBestChainLock(); + TrySignChainTip(); + LOCK(cs); + tryLockChainTipScheduled = false; + }, + 0); +} + +void CChainLocksHandler::TrySignChainTip() +{ + Cleanup(); + + const CBlockIndex* pindex; + { + LOCK(cs_main); + pindex = chainActive.Tip(); + } + if (!fMasterNode) { return; } - if (!pindexNew->pprev) { + if (!pindex->pprev) { return; } if (!sporkManager.IsSporkActive(SPORK_23_CHAINLOCKS_ENFORCEMENT)) { return; } - Cleanup(); - // DIP8 defines a process called "Signing attempts" which should run before the CLSIG is finalized // To simplify the initial implementation, we skip this process and directly try to create a CLSIG // This will fail when multiple blocks compete, but we accept this for the initial implementation. // Later, we'll add the multiple attempts process. - uint256 requestId = ::SerializeHash(std::make_pair(CLSIG_REQUESTID_PREFIX, pindexNew->nHeight)); - uint256 msgHash = pindexNew->GetBlockHash(); - { LOCK(cs); - if (bestChainLockBlockIndex == pindexNew) { - // we first got the CLSIG, then the header, and then the block was connected. - // In this case there is no need to continue here. + if (pindex->nHeight == lastSignedHeight) { + // already signed this one return; } - if (InternalHasConflictingChainLock(pindexNew->nHeight, pindexNew->GetBlockHash())) { - if (!inEnforceBestChainLock) { - // we accepted this block when there was no lock yet, but now a conflicting lock appeared. Invalidate it. - LogPrintf("CChainLocksHandler::%s -- conflicting lock after block was accepted, invalidating now\n", - __func__); - ScheduleInvalidateBlock(pindexNew); - } + if (bestChainLock.nHeight >= pindex->nHeight) { + // already got the same CLSIG or a better one return; } - if (bestChainLock.nHeight >= pindexNew->nHeight) { - // already got the same CLSIG or a better one + if (InternalHasConflictingChainLock(pindex->nHeight, pindex->GetBlockHash())) { + // don't sign if another conflicting CLSIG is already present. EnforceBestChainLock will later enforce + // the correct chain. return; } + } - if (pindexNew->nHeight == lastSignedHeight) { - // already signed this one + LogPrint(BCLog::LLMQ, "CChainLocksHandler::%s -- trying to sign %s, height=%d\n", __func__, pindex->GetBlockHash().ToString(), pindex->nHeight); + + uint256 requestId = ::SerializeHash(std::make_pair(CLSIG_REQUESTID_PREFIX, pindex->nHeight)); + uint256 msgHash = pindex->GetBlockHash(); + + { + LOCK(cs); + if (bestChainLock.nHeight >= pindex->nHeight) { + // might have happened while we didn't hold cs return; } - lastSignedHeight = pindexNew->nHeight; + lastSignedHeight = pindex->nHeight; lastSignedRequestId = requestId; lastSignedMsgHash = msgHash; } @@ -237,23 +268,30 @@ void CChainLocksHandler::UpdatedBlockTip(const CBlockIndex* pindexNew, const CBl } // WARNING: cs_main and cs should not be held! +// This should also not be called from validation signals, as this might result in recursive calls void CChainLocksHandler::EnforceBestChainLock() { CChainLockSig clsig; const CBlockIndex* pindex; + const CBlockIndex* currentBestChainLockBlockIndex; { LOCK(cs); clsig = bestChainLockWithKnownBlock; - pindex = bestChainLockBlockIndex; + pindex = currentBestChainLockBlockIndex = this->bestChainLockBlockIndex; + + if (!currentBestChainLockBlockIndex) { + // we don't have the header/block, so we can't do anything right now + return; + } } + bool activateNeeded; { LOCK(cs_main); // Go backwards through the chain referenced by clsig until we find a block that is part of the main chain. // For each of these blocks, check if there are children that are NOT part of the chain referenced by clsig // and invalidate each of them. - inEnforceBestChainLock = true; // avoid unnecessary ScheduleInvalidateBlock calls inside UpdatedBlockTip while (pindex && !chainActive.Contains(pindex)) { // Invalidate all blocks that have the same prevBlockHash but are not equal to blockHash auto itp = mapPrevBlockIndex.equal_range(pindex->pprev->GetBlockHash()); @@ -262,20 +300,27 @@ void CChainLocksHandler::EnforceBestChainLock() continue; } LogPrintf("CChainLocksHandler::%s -- CLSIG (%s) invalidates block %s\n", - __func__, bestChainLockWithKnownBlock.ToString(), jt->second->GetBlockHash().ToString()); + __func__, clsig.ToString(), jt->second->GetBlockHash().ToString()); DoInvalidateBlock(jt->second, false); } pindex = pindex->pprev; } - inEnforceBestChainLock = false; + // In case blocks from the correct chain are invalid at the moment, reconsider them. The only case where this + // can happen right now is when missing superblock triggers caused the main chain to be dismissed first. When + // the trigger later appears, this should bring us to the correct chain eventually. Please note that this does + // NOT enforce invalid blocks in any way, it just causes re-validation. + if (!currentBestChainLockBlockIndex->IsValid()) { + CValidationState state; + ReconsiderBlock(state, mapBlockIndex.at(currentBestChainLockBlockIndex->GetBlockHash())); + } + + activateNeeded = chainActive.Tip()->GetAncestor(currentBestChainLockBlockIndex->nHeight) != currentBestChainLockBlockIndex; } CValidationState state; - if (!ActivateBestChain(state)) { - LogPrintf("CChainLocksHandler::UpdatedBlockTip -- ActivateBestChain failed: %s\n", state.GetRejectReason()); - // This should not have happened and we are in a state were it's not safe to continue anymore - assert(false); + if (activateNeeded && !ActivateBestChain(state)) { + LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, state.GetRejectReason()); } } @@ -305,16 +350,6 @@ void CChainLocksHandler::HandleNewRecoveredSig(const llmq::CRecoveredSig& recove ProcessNewChainLock(-1, clsig, ::SerializeHash(clsig)); } -void CChainLocksHandler::ScheduleInvalidateBlock(const CBlockIndex* pindex) -{ - // Calls to InvalidateBlock and ActivateBestChain might result in re-invocation of the UpdatedBlockTip and other - // signals, so we can't directly call it from signal handlers. We solve this by doing the call from the scheduler - - scheduler->scheduleFromNow([this, pindex]() { - DoInvalidateBlock(pindex, true); - }, 0); -} - // WARNING, do not hold cs while calling this method as we'll otherwise run into a deadlock void CChainLocksHandler::DoInvalidateBlock(const CBlockIndex* pindex, bool activateBestChain) { @@ -328,7 +363,7 @@ void CChainLocksHandler::DoInvalidateBlock(const CBlockIndex* pindex, bool activ CValidationState state; if (!InvalidateBlock(state, params, pindex2)) { - LogPrintf("CChainLocksHandler::UpdatedBlockTip -- InvalidateBlock failed: %s\n", state.GetRejectReason()); + LogPrintf("CChainLocksHandler::%s -- InvalidateBlock failed: %s\n", __func__, state.GetRejectReason()); // This should not have happened and we are in a state were it's not safe to continue anymore assert(false); } @@ -336,7 +371,7 @@ void CChainLocksHandler::DoInvalidateBlock(const CBlockIndex* pindex, bool activ CValidationState state; if (activateBestChain && !ActivateBestChain(state)) { - LogPrintf("CChainLocksHandler::UpdatedBlockTip -- ActivateBestChain failed: %s\n", state.GetRejectReason()); + LogPrintf("CChainLocksHandler::%s -- ActivateBestChain failed: %s\n", __func__, state.GetRejectReason()); // This should not have happened and we are in a state were it's not safe to continue anymore assert(false); } diff --git a/src/llmq/quorums_chainlocks.h b/src/llmq/quorums_chainlocks.h index 6bec3b132803a..06d444cf49e35 100644 --- a/src/llmq/quorums_chainlocks.h +++ b/src/llmq/quorums_chainlocks.h @@ -45,7 +45,7 @@ class CChainLocksHandler : public CRecoveredSigsListener private: CScheduler* scheduler; RecursiveMutex cs; - std::atomic inEnforceBestChainLock{false}; + bool tryLockChainTipScheduled{false}; uint256 bestChainLockHash; CChainLockSig bestChainLock; @@ -75,6 +75,7 @@ class CChainLocksHandler : public CRecoveredSigsListener void ProcessNewChainLock(NodeId from, const CChainLockSig& clsig, const uint256& hash); void AcceptedBlockHeader(const CBlockIndex* pindexNew); void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork); + void TrySignChainTip(); void EnforceBestChainLock(); virtual void HandleNewRecoveredSig(const CRecoveredSig& recoveredSig); @@ -86,7 +87,6 @@ class CChainLocksHandler : public CRecoveredSigsListener bool InternalHasChainLock(int nHeight, const uint256& blockHash); bool InternalHasConflictingChainLock(int nHeight, const uint256& blockHash); - void ScheduleInvalidateBlock(const CBlockIndex* pindex); void DoInvalidateBlock(const CBlockIndex* pindex, bool activateBestChain); void Cleanup(); diff --git a/src/llmq/quorums_dkgsession.h b/src/llmq/quorums_dkgsession.h index 7340ee34edd2b..c7c546d79e1f0 100644 --- a/src/llmq/quorums_dkgsession.h +++ b/src/llmq/quorums_dkgsession.h @@ -10,7 +10,6 @@ #include "bls/bls_worker.h" #include "consensus/params.h" #include "evo/deterministicmns.h" -#include "evo/evodb.h" #include "net.h" #include "llmq/quorums_utils.h" #include "logging.h" @@ -237,7 +236,6 @@ class CDKGSession private: const Consensus::LLMQParams& params; - CEvoDB& evoDb; CBLSWorker& blsWorker; CBLSWorkerCache cache; CDKGSessionManager& dkgManager; @@ -277,8 +275,8 @@ class CDKGSession std::set validCommitments; public: - CDKGSession(const Consensus::LLMQParams& _params, CEvoDB& _evoDb, CBLSWorker& _blsWorker, CDKGSessionManager& _dkgManager) : - params(_params), evoDb(_evoDb), blsWorker(_blsWorker), cache(_blsWorker), dkgManager(_dkgManager) {} + CDKGSession(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker, CDKGSessionManager& _dkgManager) : + params(_params), blsWorker(_blsWorker), cache(_blsWorker), dkgManager(_dkgManager) {} bool Init(const CBlockIndex* _pindexQuorum, const std::vector& mns, const uint256& _myProTxHash); diff --git a/src/llmq/quorums_dkgsessionhandler.cpp b/src/llmq/quorums_dkgsessionhandler.cpp index c8630f00e0b3e..e105c177fb58f 100644 --- a/src/llmq/quorums_dkgsessionhandler.cpp +++ b/src/llmq/quorums_dkgsessionhandler.cpp @@ -84,12 +84,11 @@ void CDKGPendingMessages::Clear() ////// -CDKGSessionHandler::CDKGSessionHandler(const Consensus::LLMQParams& _params, CEvoDB& _evoDb, CBLSWorker& _blsWorker, CDKGSessionManager& _dkgManager) : +CDKGSessionHandler::CDKGSessionHandler(const Consensus::LLMQParams& _params, CBLSWorker& _blsWorker, CDKGSessionManager& _dkgManager) : params(_params), - evoDb(_evoDb), blsWorker(_blsWorker), dkgManager(_dkgManager), - curSession(std::make_shared(_params, _evoDb, _blsWorker, _dkgManager)), + curSession(std::make_shared(_params, _blsWorker, _dkgManager)), pendingContributions((size_t)_params.size * 2), // we allow size*2 messages as we need to make sure we see bad behavior (double messages) pendingComplaints((size_t)_params.size * 2), pendingJustifications((size_t)_params.size * 2), @@ -162,7 +161,7 @@ void CDKGSessionHandler::StopThread() bool CDKGSessionHandler::InitNewQuorum(const CBlockIndex* pindexQuorum) { - curSession = std::make_shared(params, evoDb, blsWorker, dkgManager); + curSession = std::make_shared(params, blsWorker, dkgManager); if (!deterministicMNManager->IsDIP3Enforced(pindexQuorum->nHeight) || !activeMasternodeManager) { @@ -591,7 +590,7 @@ void CDKGSessionHandler::PhaseHandlerThread() status.aborted = true; return true; }); - LogPrintf("CDKGSessionHandler::%s -- aborted current DKG session\n", __func__); + LogPrintf("CDKGSessionHandler::%s -- aborted current DKG session for llmq=%s\n", __func__, params.name); } } } diff --git a/src/llmq/quorums_dkgsessionhandler.h b/src/llmq/quorums_dkgsessionhandler.h index 5b212daa4db6b..d745938b9cc8d 100644 --- a/src/llmq/quorums_dkgsessionhandler.h +++ b/src/llmq/quorums_dkgsessionhandler.h @@ -100,7 +100,6 @@ class CDKGSessionHandler std::atomic stopRequested{false}; const Consensus::LLMQParams& params; - CEvoDB& evoDb; CBLSWorker& blsWorker; CDKGSessionManager& dkgManager; @@ -117,7 +116,7 @@ class CDKGSessionHandler CDKGPendingMessages pendingPrematureCommitments; public: - CDKGSessionHandler(const Consensus::LLMQParams& _params, CEvoDB& _evoDb, CBLSWorker& blsWorker, CDKGSessionManager& _dkgManager); + CDKGSessionHandler(const Consensus::LLMQParams& _params, CBLSWorker& blsWorker, CDKGSessionManager& _dkgManager); ~CDKGSessionHandler(); void UpdatedBlockTip(const CBlockIndex *pindexNew); diff --git a/src/llmq/quorums_dkgsessionmgr.cpp b/src/llmq/quorums_dkgsessionmgr.cpp index 296444954de83..2c8dd0490ef27 100644 --- a/src/llmq/quorums_dkgsessionmgr.cpp +++ b/src/llmq/quorums_dkgsessionmgr.cpp @@ -19,14 +19,13 @@ std::unique_ptr quorumDKGSessionManager{nullptr}; static const std::string DB_VVEC = "qdkg_V"; static const std::string DB_SKCONTRIB = "qdkg_S"; -CDKGSessionManager::CDKGSessionManager(CEvoDB& _evoDb, CBLSWorker& _blsWorker) : - evoDb(_evoDb), - blsWorker(_blsWorker) +CDKGSessionManager::CDKGSessionManager(CDBWrapper& _llmqDb, CBLSWorker& _blsWorker) : llmqDb(_llmqDb), + blsWorker(_blsWorker) { for (const auto& qt : Params().GetConsensus().llmqs) { dkgSessionHandlers.emplace(std::piecewise_construct, std::forward_as_tuple(qt.first), - std::forward_as_tuple(qt.second, evoDb, blsWorker, *this)); + std::forward_as_tuple(qt.second, blsWorker, *this)); } } @@ -160,12 +159,12 @@ bool CDKGSessionManager::GetPrematureCommitment(const uint256& hash, CDKGPrematu void CDKGSessionManager::WriteVerifiedVvecContribution(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& proTxHash, const BLSVerificationVectorPtr& vvec) { - evoDb.GetRawDB().Write(std::make_tuple(DB_VVEC, (uint8_t)llmqType, pindexQuorum->GetBlockHash(), proTxHash), *vvec); + llmqDb.Write(std::make_tuple(DB_VVEC, (uint8_t)llmqType, pindexQuorum->GetBlockHash(), proTxHash), *vvec); } void CDKGSessionManager::WriteVerifiedSkContribution(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const uint256& proTxHash, const CBLSSecretKey& skContribution) { - evoDb.GetRawDB().Write(std::make_tuple(DB_SKCONTRIB, (uint8_t)llmqType, pindexQuorum->GetBlockHash(), proTxHash), skContribution); + llmqDb.Write(std::make_tuple(DB_SKCONTRIB, (uint8_t)llmqType, pindexQuorum->GetBlockHash(), proTxHash), skContribution); } bool CDKGSessionManager::GetVerifiedContributions(Consensus::LLMQType llmqType, const CBlockIndex* pindexQuorum, const std::vector& validMembers, std::vector& memberIndexesRet, std::vector& vvecsRet, BLSSecretKeyVector& skContributionsRet) @@ -209,10 +208,10 @@ bool CDKGSessionManager::GetVerifiedContribution(Consensus::LLMQType llmqType, c BLSVerificationVector vvec; BLSVerificationVectorPtr vvecPtr; CBLSSecretKey skContribution; - if (evoDb.GetRawDB().Read(std::make_tuple(DB_VVEC, (uint8_t)llmqType, quorumHash, proTxHash), vvec)) { + if (llmqDb.Read(std::make_tuple(DB_VVEC, (uint8_t)llmqType, quorumHash, proTxHash), vvec)) { vvecPtr = std::make_shared(std::move(vvec)); } - evoDb.GetRawDB().Read(std::make_tuple(DB_SKCONTRIB, (uint8_t)llmqType, quorumHash, proTxHash), skContribution); + llmqDb.Read(std::make_tuple(DB_SKCONTRIB, (uint8_t)llmqType, quorumHash, proTxHash), skContribution); it = contributionsCache.emplace(cacheKey, ContributionsCacheEntry{GetTimeMillis(), vvecPtr, skContribution}).first; diff --git a/src/llmq/quorums_dkgsessionmgr.h b/src/llmq/quorums_dkgsessionmgr.h index bbe078343861e..c2284b2adcd43 100644 --- a/src/llmq/quorums_dkgsessionmgr.h +++ b/src/llmq/quorums_dkgsessionmgr.h @@ -20,7 +20,7 @@ class CDKGSessionManager static const int64_t MAX_CONTRIBUTION_CACHE_TIME = 60 * 1000; private: - CEvoDB& evoDb; + CDBWrapper& llmqDb; CBLSWorker& blsWorker; std::map dkgSessionHandlers; @@ -45,7 +45,7 @@ class CDKGSessionManager std::map contributionsCache; public: - CDKGSessionManager(CEvoDB& _evoDb, CBLSWorker& _blsWorker); + CDKGSessionManager(CDBWrapper& _evoDb, CBLSWorker& _blsWorker); ~CDKGSessionManager() {}; void StartThreads(); diff --git a/src/llmq/quorums_init.cpp b/src/llmq/quorums_init.cpp index 87bd3320baa1b..d272d7bc1e8aa 100644 --- a/src/llmq/quorums_init.cpp +++ b/src/llmq/quorums_init.cpp @@ -6,6 +6,7 @@ #include "llmq/quorums_init.h" #include "bls/bls_worker.h" +#include "dbwrapper.h" #include "llmq/quorums.h" #include "llmq/quorums_blockprocessor.h" #include "llmq/quorums_debug.h" @@ -18,17 +19,19 @@ namespace llmq { CBLSWorker* blsWorker; +CDBWrapper* llmqDb; void InitLLMQSystem(CEvoDB& evoDb, CScheduler* scheduler, bool unitTests) { + llmqDb = new CDBWrapper(unitTests ? "" : (GetDataDir() / "llmq"), 1 << 20, unitTests, false, CLIENT_VERSION | ADDRV2_FORMAT); blsWorker = new CBLSWorker(); quorumDKGDebugManager.reset(new CDKGDebugManager()); quorumBlockProcessor.reset(new CQuorumBlockProcessor(evoDb)); - quorumDKGSessionManager.reset(new CDKGSessionManager(evoDb, *blsWorker)); + quorumDKGSessionManager.reset(new CDKGSessionManager(*llmqDb, *blsWorker)); quorumManager.reset(new CQuorumManager(evoDb, *blsWorker, *quorumDKGSessionManager)); quorumSigSharesManager.reset(new CSigSharesManager()); - quorumSigningManager.reset(new CSigningManager(unitTests)); + quorumSigningManager.reset(new CSigningManager(*llmqDb, unitTests)); chainLocksHandler.reset(new CChainLocksHandler(scheduler)); } @@ -43,6 +46,8 @@ void DestroyLLMQSystem() quorumManager.reset(); delete blsWorker; blsWorker = nullptr; + delete llmqDb; + llmqDb = nullptr; } void StartLLMQSystem() diff --git a/src/llmq/quorums_init.h b/src/llmq/quorums_init.h index cc56b5ff7c5c7..0f4e3b852cc3c 100644 --- a/src/llmq/quorums_init.h +++ b/src/llmq/quorums_init.h @@ -14,6 +14,8 @@ class CEvoDB; namespace llmq { +extern CDBWrapper* llmqDb; + // Init/destroy LLMQ globals void InitLLMQSystem(CEvoDB& evoDb, CScheduler* scheduler, bool unitTests); void DestroyLLMQSystem(); diff --git a/src/llmq/quorums_signing.cpp b/src/llmq/quorums_signing.cpp index 34a1a9816bfc4..eb9d13c9ddbc8 100644 --- a/src/llmq/quorums_signing.cpp +++ b/src/llmq/quorums_signing.cpp @@ -24,84 +24,75 @@ namespace llmq std::unique_ptr quorumSigningManager{nullptr}; -CRecoveredSigsDb::CRecoveredSigsDb(bool fMemory) : db(fMemory ? "" : (GetDataDir() / "llmq"), 1 << 20, fMemory, false, CLIENT_VERSION | ADDRV2_FORMAT) +CRecoveredSigsDb::CRecoveredSigsDb(CDBWrapper& _db) : db(_db) { } bool CRecoveredSigsDb::HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) { - auto k = std::make_tuple('r', (uint8_t)llmqType, id, msgHash); + auto k = std::make_tuple(std::string("rs_r"), (uint8_t)llmqType, id, msgHash); return db.Exists(k); } bool CRecoveredSigsDb::HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id) { - int64_t t = GetTimeMillis(); - auto cacheKey = std::make_pair(llmqType, id); + bool ret; { LOCK(cs); - auto it = hasSigForIdCache.find(cacheKey); - if (it != hasSigForIdCache.end()) { - it->second.second = t; - return it->second.first; + if (hasSigForIdCache.get(cacheKey, ret)) { + return ret; } } - auto k = std::make_tuple('r', (uint8_t)llmqType, id); - bool ret = db.Exists(k); + auto k = std::make_tuple(std::string("rs_r"), (uint8_t)llmqType, id); + ret = db.Exists(k); LOCK(cs); - hasSigForIdCache.emplace(cacheKey, std::make_pair(ret, t)); + hasSigForIdCache.insert(cacheKey, ret); return ret; } bool CRecoveredSigsDb::HasRecoveredSigForSession(const uint256& signHash) { - int64_t t = GetTimeMillis(); - + bool ret; { LOCK(cs); - auto it = hasSigForSessionCache.find(signHash); - if (it != hasSigForSessionCache.end()) { - it->second.second = t; - return it->second.first; + if (hasSigForSessionCache.get(signHash, ret)) { + return ret; } } - auto k = std::make_tuple('s', signHash); - bool ret = db.Exists(k); + auto k = std::make_tuple(std::string("rs_s"), signHash); + ret = db.Exists(k); LOCK(cs); - hasSigForSessionCache.emplace(signHash, std::make_pair(ret, t)); + hasSigForSessionCache.insert(signHash, ret); return ret; } bool CRecoveredSigsDb::HasRecoveredSigForHash(const uint256& hash) { - int64_t t = GetTimeMillis(); - + bool ret; { LOCK(cs); - auto it = hasSigForHashCache.find(hash); - if (it != hasSigForHashCache.end()) { - it->second.second = t; - return it->second.first; + if (hasSigForHashCache.get(hash, ret)) { + return ret; } } - auto k = std::make_tuple('h', hash); - bool ret = db.Exists(k); + auto k = std::make_tuple(std::string("rs_h"), hash); + ret = db.Exists(k); LOCK(cs); - hasSigForHashCache.emplace(hash, std::make_pair(ret, t)); + hasSigForHashCache.insert(hash, ret); return ret; } bool CRecoveredSigsDb::ReadRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, CRecoveredSig& ret) { - auto k = std::make_tuple('r', (uint8_t)llmqType, id); + auto k = std::make_tuple(std::string("rs_r"), (uint8_t)llmqType, id); CDataStream ds(SER_DISK, CLIENT_VERSION); if (!db.ReadDataStream(k, ds)) { @@ -118,7 +109,7 @@ bool CRecoveredSigsDb::ReadRecoveredSig(Consensus::LLMQType llmqType, const uint bool CRecoveredSigsDb::GetRecoveredSigByHash(const uint256& hash, CRecoveredSig& ret) { - auto k1 = std::make_tuple('h', hash); + auto k1 = std::make_tuple(std::string("rs_h"), hash); std::pair k2; if (!db.Read(k1, k2)) { return false; @@ -138,26 +129,26 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig) // we put these close to each other to leverage leveldb's key compaction // this way, the second key can be used for fast HasRecoveredSig checks while the first key stores the recSig - auto k1 = std::make_tuple('r', recSig.llmqType, recSig.id); - auto k2 = std::make_tuple('r', recSig.llmqType, recSig.id, recSig.msgHash); + auto k1 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id); + auto k2 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id, recSig.msgHash); batch.Write(k1, recSig); batch.Write(k2, (uint8_t)1); // store by object hash - auto k3 = std::make_tuple('h', recSig.GetHash()); + auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash()); batch.Write(k3, std::make_pair(recSig.llmqType, recSig.id)); // store by signHash auto signHash = llmq::utils::BuildSignHash(recSig); - auto k4 = std::make_tuple('s', signHash); + auto k4 = std::make_tuple(std::string("rs_s"), signHash); batch.Write(k4, (uint8_t)1); // remove the votedForId entry as we won't need it anymore - auto k5 = std::make_tuple('v', recSig.llmqType, recSig.id); + auto k5 = std::make_tuple(std::string("rs_v"), recSig.llmqType, recSig.id); batch.Erase(k5); // store by current time. Allows fast cleanup of old recSigs - auto k6 = std::make_tuple('t', (uint32_t)GetAdjustedTime(), recSig.llmqType, recSig.id); + auto k6 = std::make_tuple(std::string("rs_t"), (uint32_t)GetAdjustedTime(), recSig.llmqType, recSig.id); batch.Write(k6, (uint8_t)1); db.WriteBatch(batch); @@ -166,34 +157,9 @@ void CRecoveredSigsDb::WriteRecoveredSig(const llmq::CRecoveredSig& recSig) int64_t t = GetTimeMillis(); LOCK(cs); - hasSigForIdCache[std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id)] = std::make_pair(true, t); - hasSigForSessionCache[signHash] = std::make_pair(true, t); - hasSigForHashCache[recSig.GetHash()] = std::make_pair(true, t); - } -} - -template -static void TruncateCacheMap(std::unordered_map, H>& m, size_t maxSize, size_t truncateThreshold) -{ - typedef typename std::unordered_map, H> Map; - typedef typename Map::iterator Iterator; - - if (m.size() <= truncateThreshold) { - return; - } - - std::vector vec; - vec.reserve(m.size()); - for (auto it = m.begin(); it != m.end(); ++it) { - vec.emplace_back(it); - } - // sort by last access time (descending order) - std::sort(vec.begin(), vec.end(), [](const Iterator& it1, const Iterator& it2) { - return it1->second.second > it2->second.second; - }); - - for (size_t i = maxSize; i < vec.size(); i++) { - m.erase(vec[i]); + hasSigForIdCache.insert(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.id), true); + hasSigForSessionCache.insert(signHash, true); + hasSigForHashCache.insert(recSig.GetHash(), true); } } @@ -202,8 +168,8 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge) std::unique_ptr pcursor(db.NewIterator()); static const uint256 maxUint256 = uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - auto start = std::make_tuple('t', (uint32_t)0, (uint8_t)0, uint256()); - auto end = std::make_tuple('t', (uint32_t)(GetAdjustedTime() - maxAge), (uint8_t)255, maxUint256); + auto start = std::make_tuple(std::string("rs_t"), (uint32_t)0, (uint8_t)0, uint256()); + auto end = std::make_tuple(std::string("rs_t"), (uint32_t)(GetAdjustedTime() - maxAge), (uint8_t)255, maxUint256); pcursor->Seek(start); std::vector> toDelete; @@ -241,11 +207,11 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge) auto signHash = llmq::utils::BuildSignHash(recSig); - auto k1 = std::make_tuple('r', recSig.llmqType, recSig.id); - auto k2 = std::make_tuple('r', recSig.llmqType, recSig.id, recSig.msgHash); - auto k3 = std::make_tuple('h', recSig.GetHash()); - auto k4 = std::make_tuple('s', signHash); - auto k5 = std::make_tuple('v', recSig.llmqType, recSig.id); + auto k1 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id); + auto k2 = std::make_tuple(std::string("rs_r"), recSig.llmqType, recSig.id, recSig.msgHash); + auto k3 = std::make_tuple(std::string("rs_h"), recSig.GetHash()); + auto k4 = std::make_tuple(std::string("rs_s"), signHash); + auto k5 = std::make_tuple(std::string("rs_v"), recSig.llmqType, recSig.id); batch.Erase(k1); batch.Erase(k2); batch.Erase(k3); @@ -256,10 +222,6 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge) hasSigForSessionCache.erase(signHash); hasSigForHashCache.erase(recSig.GetHash()); } - - TruncateCacheMap(hasSigForIdCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD); - TruncateCacheMap(hasSigForSessionCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD); - TruncateCacheMap(hasSigForHashCache, MAX_CACHE_SIZE, MAX_CACHE_TRUNCATE_THRESHOLD); } for (auto& e : toDelete2) { @@ -271,25 +233,25 @@ void CRecoveredSigsDb::CleanupOldRecoveredSigs(int64_t maxAge) bool CRecoveredSigsDb::HasVotedOnId(Consensus::LLMQType llmqType, const uint256& id) { - auto k = std::make_tuple('v', (uint8_t)llmqType, id); + auto k = std::make_tuple(std::string("rs_v"), (uint8_t)llmqType, id); return db.Exists(k); } bool CRecoveredSigsDb::GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet) { - auto k = std::make_tuple('v', (uint8_t)llmqType, id); + auto k = std::make_tuple(std::string("rs_v"), (uint8_t)llmqType, id); return db.Read(k, msgHashRet); } void CRecoveredSigsDb::WriteVoteForId(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) { - auto k = std::make_tuple('v', (uint8_t)llmqType, id); + auto k = std::make_tuple(std::string("rs_v"), (uint8_t)llmqType, id); db.Write(k, msgHash); } ////////////////// -CSigningManager::CSigningManager(bool fMemory) : db(fMemory) +CSigningManager::CSigningManager(CDBWrapper& llmqDb, bool fMemory) : db(llmqDb) { } @@ -337,7 +299,7 @@ void CSigningManager::ProcessMessageRecoveredSig(CNode* pfrom, const CRecoveredS return; } - LogPrintf("llmq", "CSigningManager::%s -- signHash=%s, node=%d\n", __func__, llmq::utils::BuildSignHash(recoveredSig).ToString(), pfrom->GetId()); + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- signHash=%s, node=%d\n", __func__, llmq::utils::BuildSignHash(recoveredSig).ToString(), pfrom->GetId()); LOCK(cs); pendingRecoveredSigs[pfrom->GetId()].emplace_back(recoveredSig); @@ -356,7 +318,7 @@ bool CSigningManager::PreVerifyRecoveredSig(NodeId nodeId, const CRecoveredSig& CQuorumCPtr quorum = quorumManager->GetQuorum(llmqType, recoveredSig.quorumHash); if (!quorum) { - LogPrintf("CSigningManager::%s -- quorum %s not found, node=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not found, node=%d\n", __func__, recoveredSig.quorumHash.ToString(), nodeId); return false; } @@ -415,13 +377,13 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify( if (!retQuorums.count(quorumKey)) { CQuorumCPtr quorum = quorumManager->GetQuorum(llmqType, recSig.quorumHash); if (!quorum) { - LogPrintf("CSigningManager::%s -- quorum %s not found, node=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not found, node=%d\n", __func__, recSig.quorumHash.ToString(), nodeId); it = v.erase(it); continue; } if (!llmq::utils::IsQuorumActive(llmqType, quorum->pindexQuorum->GetBlockHash())) { - LogPrintf("CSigningManager::%s -- quorum %s not active anymore, node=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not active anymore, node=%d\n", __func__, recSig.quorumHash.ToString(), nodeId); it = v.erase(it); continue; @@ -456,7 +418,7 @@ bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman) for (auto& recSig : v) { const auto& quorum = quorums.at(std::make_pair((Consensus::LLMQType)recSig.llmqType, recSig.quorumHash)); - batchVerifier.PushMessage(nodeId, recSig.GetHash(), llmq::utils::BuildSignHash(recSig), recSig.sig, quorum->quorumPublicKey); + batchVerifier.PushMessage(nodeId, recSig.GetHash(), llmq::utils::BuildSignHash(recSig), recSig.sig, quorum->qc.quorumPublicKey); verifyCount++; } } @@ -465,7 +427,7 @@ bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman) batchVerifier.Verify(); verifyTimer.stop(); - LogPrintf("llmq", "CSigningManager::%s -- verified recovered sig(s). count=%d, vt=%d, nodes=%d\n", __func__, verifyCount, verifyTimer.count(), recSigsByNode.size()); + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- verified recovered sig(s). count=%d, vt=%d, nodes=%d\n", __func__, verifyCount, verifyTimer.count(), recSigsByNode.size()); std::unordered_set processed; for (auto& p : recSigsByNode) { @@ -474,7 +436,7 @@ bool CSigningManager::ProcessPendingRecoveredSigs(CConnman& connman) if (batchVerifier.badSources.count(nodeId)) { LOCK(cs_main); - LogPrintf("llmq", "CSigningManager::%s -- invalid recSig from other node, banning peer=%d\n", __func__, nodeId); + LogPrintf("CSigningManager::%s -- invalid recSig from other node, banning peer=%d\n", __func__, nodeId); Misbehaving(nodeId, 100); continue; } @@ -508,7 +470,7 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re auto signHash = llmq::utils::BuildSignHash(recoveredSig); - LogPrintf("CSigningManager::%s -- valid recSig. signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- valid recSig. signHash=%s, id=%s, msgHash=%s, node=%d\n", __func__, signHash.ToString(), recoveredSig.id.ToString(), recoveredSig.msgHash.ToString(), nodeId); if (db.HasRecoveredSigForId(llmqType, recoveredSig.id)) { @@ -537,7 +499,11 @@ void CSigningManager::ProcessRecoveredSig(NodeId nodeId, const CRecoveredSig& re } CInv inv(MSG_QUORUM_RECOVERED_SIG, recoveredSig.GetHash()); - g_connman->RelayInv(inv); + g_connman->ForEachNode([&](CNode* pnode) { + if (pnode->m_wants_recsigs) { + pnode->PushInventory(inv); + } + }); for (auto& l : listeners) { l->HandleNewRecoveredSig(recoveredSig); } @@ -588,7 +554,7 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint LogPrintf("CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting on conflicting msgHash=%s\n", __func__, id.ToString(), prevMsgHash.ToString(), msgHash.ToString()); } else { - LogPrintf("CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting again.\n", __func__, + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- already voted for id=%s and msgHash=%s. Not voting again.\n", __func__, id.ToString(), prevMsgHash.ToString()); } return false; @@ -614,12 +580,12 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, const uint // TODO fix this by re-signing when the next block arrives, but only when that block results in a change of the quorum list and no recovered signature has been created in the mean time CQuorumCPtr quorum = SelectQuorumForSigning(llmqType, tipHeight, id); if (!quorum) { - LogPrintf("CSigningManager::%s -- failed to select quorum. id=%s, msgHash=%s\n", __func__, id.ToString(), msgHash.ToString()); + LogPrint(BCLog::LLMQ, "CSigningManager::%s -- failed to select quorum. id=%s, msgHash=%s\n", __func__, id.ToString(), msgHash.ToString()); return false; } if (!quorum->IsValidMember(activeMasternodeManager->GetProTx())) { - // LogPrintf("CSigningManager::%s -- we're not a valid member of quorum %s\n", __func__, quorum->quorumHash.ToString()); + // LogPrint(BCLog::LLMQ, "CSigningManager::%s -- we're not a valid member of quorum %s\n", __func__, quorum->quorumHash.ToString()); return false; } @@ -659,6 +625,16 @@ bool CSigningManager::IsConflicting(Consensus::LLMQType llmqType, const uint256& return false; } +bool CSigningManager::HasVotedOnId(Consensus::LLMQType llmqType, const uint256& id) +{ + return db.HasVotedOnId(llmqType, id); +} + +bool CSigningManager::GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet) +{ + return db.GetVoteForId(llmqType, id, msgHashRet); +} + CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType, int signHeight, const uint256& selectionHash) { auto& llmqParams = Params().GetConsensus().llmqs.at(llmqType); @@ -702,7 +678,7 @@ bool CSigningManager::VerifyRecoveredSig(Consensus::LLMQType llmqType, int signe } uint256 signHash = llmq::utils::BuildSignHash(llmqParams.type, quorum->pindexQuorum->GetBlockHash(), id, msgHash); - return sig.VerifyInsecure(quorum->quorumPublicKey, signHash); + return sig.VerifyInsecure(quorum->qc.quorumPublicKey, signHash); } -} // namespace llmq \ No newline at end of file +} // namespace llmq diff --git a/src/llmq/quorums_signing.h b/src/llmq/quorums_signing.h index d4616d683f30c..a68bded653b3f 100644 --- a/src/llmq/quorums_signing.h +++ b/src/llmq/quorums_signing.h @@ -12,6 +12,7 @@ #include "net.h" #include "saltedhasher.h" #include "sync.h" +#include "unordered_lru_cache.h" #include @@ -69,19 +70,16 @@ class CRecoveredSig class CRecoveredSigsDb { - static const size_t MAX_CACHE_SIZE = 30000; - static const size_t MAX_CACHE_TRUNCATE_THRESHOLD = 50000; - private: - CDBWrapper db; + CDBWrapper& db; RecursiveMutex cs; - std::unordered_map, std::pair, StaticSaltedHasher> hasSigForIdCache; - std::unordered_map, StaticSaltedHasher> hasSigForSessionCache; - std::unordered_map, StaticSaltedHasher> hasSigForHashCache; + unordered_lru_cache, bool, StaticSaltedHasher, 30000> hasSigForIdCache; + unordered_lru_cache hasSigForSessionCache; + unordered_lru_cache hasSigForHashCache; public: - CRecoveredSigsDb(bool fMemory); + CRecoveredSigsDb(CDBWrapper& _db); bool HasRecoveredSig(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash); bool HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id); @@ -136,7 +134,7 @@ class CSigningManager std::vector recoveredSigsListeners; public: - CSigningManager(bool fMemory); + CSigningManager(CDBWrapper& llmqDb, bool fMemory); bool AlreadyHave(const CInv& inv); bool GetRecoveredSigForGetData(const uint256& hash, CRecoveredSig& ret); @@ -163,6 +161,8 @@ class CSigningManager bool HasRecoveredSigForId(Consensus::LLMQType llmqType, const uint256& id); bool HasRecoveredSigForSession(const uint256& signHash); bool IsConflicting(Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash); + bool HasVotedOnId(Consensus::LLMQType llmqType, const uint256& id); + bool GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet); CQuorumCPtr SelectQuorumForSigning(Consensus::LLMQType llmqType, int signHeight, const uint256& selectionHash); // Verifies a recovered sig that was signed while the chain tip was at signedAtTip bool VerifyRecoveredSig(Consensus::LLMQType llmqType, int signedAtHeight, const uint256& id, const uint256& msgHash, const CBLSSignature& sig); diff --git a/src/llmq/quorums_signing_shares.cpp b/src/llmq/quorums_signing_shares.cpp index ad8fa26f0c437..0c6d5fd7bfacc 100644 --- a/src/llmq/quorums_signing_shares.cpp +++ b/src/llmq/quorums_signing_shares.cpp @@ -227,7 +227,7 @@ void CSigSharesManager::ProcessMessage(CNode* pfrom, const std::string& strComma std::vector msgs; vRecv >> msgs; if (msgs.size() > MAX_MSGS_CNT_QSIGSESANN) { - LogPrintf("llmq", "CSigSharesManager::%s -- too many announcements in QSIGSESANN message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QSIGSESANN, pfrom->GetId()); + LogPrintf("CSigSharesManager::%s -- too many announcements in QSIGSESANN message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QSIGSESANN, pfrom->GetId()); BanNode(pfrom->GetId()); return; } @@ -241,7 +241,7 @@ void CSigSharesManager::ProcessMessage(CNode* pfrom, const std::string& strComma std::vector msgs; vRecv >> msgs; if (msgs.size() > MAX_MSGS_CNT_QSIGSHARESINV) { - LogPrintf("llmq", "CSigSharesManager::%s -- too many invs in QSIGSHARESINV message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QSIGSHARESINV, pfrom->GetId()); + LogPrintf("CSigSharesManager::%s -- too many invs in QSIGSHARESINV message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QSIGSHARESINV, pfrom->GetId()); BanNode(pfrom->GetId()); return; } @@ -255,7 +255,7 @@ void CSigSharesManager::ProcessMessage(CNode* pfrom, const std::string& strComma std::vector msgs; vRecv >> msgs; if (msgs.size() > MAX_MSGS_CNT_QGETSIGSHARES) { - LogPrintf("llmq", "CSigSharesManager::%s -- too many invs in QGETSIGSHARES message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QGETSIGSHARES, pfrom->GetId()); + LogPrintf("CSigSharesManager::%s -- too many invs in QGETSIGSHARES message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_CNT_QGETSIGSHARES, pfrom->GetId()); BanNode(pfrom->GetId()); return; } @@ -273,7 +273,7 @@ void CSigSharesManager::ProcessMessage(CNode* pfrom, const std::string& strComma totalSigsCount += bs.sigShares.size(); } if (totalSigsCount > MAX_MSGS_TOTAL_BATCHED_SIGS) { - LogPrintf("llmq", "CSigSharesManager::%s -- too many sigs in QBSIGSHARES message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_TOTAL_BATCHED_SIGS, pfrom->GetId()); + LogPrintf("CSigSharesManager::%s -- too many sigs in QBSIGSHARES message. cnt=%d, max=%d, node=%d\n", __func__, msgs.size(), MAX_MSGS_TOTAL_BATCHED_SIGS, pfrom->GetId()); BanNode(pfrom->GetId()); return; } @@ -296,12 +296,12 @@ bool CSigSharesManager::ProcessMessageSigSesAnn(CNode* pfrom, const CSigSesAnn& return false; } - LogPrintf("llmq", "CSigSharesManager::%s -- ann={%s}, node=%d\n", __func__, ann.ToString(), pfrom->GetId()); + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- ann={%s}, node=%d\n", __func__, ann.ToString(), pfrom->GetId()); auto quorum = quorumManager->GetQuorum(llmqType, ann.quorumHash); if (!quorum) { // TODO should we ban here? - LogPrintf("CSigSharesManager::%s -- quorum %s not found, node=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- quorum %s not found, node=%d\n", __func__, ann.quorumHash.ToString(), pfrom->GetId()); return true; // let's still try other announcements from the same message } @@ -346,12 +346,12 @@ bool CSigSharesManager::ProcessMessageSigSharesInv(CNode* pfrom, const CSigShare return true; } - LogPrintf("llmq", "CSigSharesManager::%s -- signHash=%s, inv={%s}, node=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, inv={%s}, node=%d\n", __func__, sessionInfo.signHash.ToString(), inv.ToString(), pfrom->GetId()); if (sessionInfo.quorum->quorumVvec == nullptr) { // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG - LogPrintf("CSigSharesManager::%s -- we don't have the quorum vvec for %s, not requesting sig shares. node=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, not requesting sig shares. node=%d\n", __func__, sessionInfo.quorumHash.ToString(), pfrom->GetId()); return true; } @@ -383,7 +383,7 @@ bool CSigSharesManager::ProcessMessageGetSigShares(CNode* pfrom, const CSigShare return true; } - LogPrintf("llmq", "CSigSharesManager::%s -- signHash=%s, inv={%s}, node=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signHash=%s, inv={%s}, node=%d\n", __func__, sessionInfo.signHash.ToString(), inv.ToString(), pfrom->GetId()); LOCK(cs); @@ -406,7 +406,7 @@ bool CSigSharesManager::ProcessMessageBatchedSigShares(CNode* pfrom, const CBatc bool ban = false; if (!PreVerifyBatchedSigShares(pfrom->GetId(), sessionInfo, batchedSigShares, ban)) { - return ban; + return !ban; } std::vector sigShares; @@ -466,7 +466,7 @@ bool CSigSharesManager::PreVerifyBatchedSigShares(NodeId nodeId, const CSigShare } if (session.quorum->quorumVvec == nullptr) { // TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG - LogPrintf("CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible. node=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible. node=%d\n", __func__, session.quorumHash.ToString(), nodeId); return false; } @@ -485,7 +485,7 @@ bool CSigSharesManager::PreVerifyBatchedSigShares(NodeId nodeId, const CSigShare retBan = true; return false; } - if (!session.quorum->validMembers[quorumMember]) { + if (!session.quorum->qc.validMembers[quorumMember]) { LogPrintf("CSigSharesManager::%s -- quorumMember not valid\n", __func__); retBan = true; return false; @@ -604,14 +604,14 @@ bool CSigSharesManager::ProcessPendingSigShares(CConnman& connman) batchVerifier.Verify(); verifyTimer.stop(); - LogPrintf("llmq", "CSigSharesManager::%s -- verified sig shares. count=%d, vt=%d, nodes=%d\n", __func__, verifyCount, verifyTimer.count(), sigSharesByNodes.size()); + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- verified sig shares. count=%d, vt=%d, nodes=%d\n", __func__, verifyCount, verifyTimer.count(), sigSharesByNodes.size()); for (auto& p : sigSharesByNodes) { auto nodeId = p.first; auto& v = p.second; if (batchVerifier.badSources.count(nodeId)) { - LogPrintf("llmq", "CSigSharesManager::%s -- invalid sig shares from other node, banning peer=%d\n", + LogPrintf("CSigSharesManager::%s -- invalid sig shares from other node, banning peer=%d\n", __func__, nodeId); // this will also cause re-requesting of the shares that were sent by this node BanNode(nodeId); @@ -635,18 +635,12 @@ void CSigSharesManager::ProcessPendingSigSharesFromNode(NodeId nodeId, cxxtimer::Timer t(true); for (auto& sigShare : sigShares) { - // he sent us some valid sig shares, so he must be part of this quorum and is thus interested in our sig shares as well - // if this is the first time we received a sig share from this node, we won't announce the currently locally known sig shares to him. - // only the upcoming sig shares will be announced to him. this means the first signing session for a fresh quorum will be a bit - // slower than for older ones. TODO: fix this (risk of DoS when announcing all at once?) auto quorumKey = std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash); - nodeState.interestedIn.emplace(quorumKey); - ProcessSigShare(nodeId, sigShare, connman, quorums.at(quorumKey)); } t.stop(); - LogPrintf("llmq", "CSigSharesManager::%s -- processed sigShare batch. shares=%d, time=%d, node=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- processed sigShare batch. shares=%d, time=%d, node=%d\n", __func__, sigShares.size(), t.count(), nodeId); } @@ -661,10 +655,6 @@ void CSigSharesManager::ProcessSigShare(NodeId nodeId, const CSigShare& sigShare std::set quorumNodes; if (sigShare.quorumMember == quorum->GetMemberIndex(activeMasternodeManager->GetProTx())) { quorumNodes = connman.GetTierTwoConnMan()->getQuorumNodes((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash); - // make sure node states are created for these nodes (we might have not received any message from these yet) - for (auto otherNodeId : quorumNodes) { - nodeStates[otherNodeId].interestedIn.emplace(std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash)); - } } if (quorumSigningManager->HasRecoveredSigForId(llmqType, sigShare.id)) { @@ -693,12 +683,9 @@ void CSigSharesManager::ProcessSigShare(NodeId nodeId, const CSigShare& sigShare if (!quorumNodes.empty()) { // don't announce and wait for other nodes to request this share and directly send it to them // there is no way the other nodes know about this share as this is the one created on this node - // this will also indicate interest to the other nodes in sig shares for this quorum - for (auto& p : nodeStates) { - if (!quorumNodes.count(p.first) && !p.second.interestedIn.count(std::make_pair((Consensus::LLMQType)sigShare.llmqType, sigShare.quorumHash))) { - continue; - } - auto& session = p.second.GetOrCreateSessionFromShare(sigShare); + for (auto otherNodeId : quorumNodes) { + auto& nodeState = nodeStates[otherNodeId]; + auto& session = nodeState.GetOrCreateSessionFromShare(sigShare); session.quorum = quorum; session.requested.Set(sigShare.quorumMember, true); session.knows.Set(sigShare.quorumMember, true); @@ -758,7 +745,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& return; } - LogPrintf("CSigSharesManager::%s -- recovered signature. id=%s, msgHash=%s, time=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- recovered signature. id=%s, msgHash=%s, time=%d\n", __func__, id.ToString(), msgHash.ToString(), t.count()); CRecoveredSig rs; @@ -770,7 +757,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& rs.UpdateHash(); auto signHash = llmq::utils::BuildSignHash(rs); - bool valid = rs.sig.VerifyInsecure(quorum->quorumPublicKey, signHash); + bool valid = rs.sig.VerifyInsecure(quorum->qc.quorumPublicKey, signHash); if (!valid) { // this should really not happen as we have verified all signature shares before LogPrintf("CSigSharesManager::%s -- own recovered signature is invalid. id=%s, msgHash=%s\n", __func__, @@ -781,9 +768,10 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& quorumSigningManager->ProcessRecoveredSig(-1, rs, quorum, connman); } -// cs must be held void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map>& sigSharesToRequest) { + AssertLockHeld(cs); + int64_t now = GetTimeMillis(); const size_t maxRequestsForNode = 32; @@ -808,7 +796,7 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map= SIG_SHARE_REQUEST_TIMEOUT) { // timeout while waiting for this one, so retry it with another node - LogPrintf("llmq", "CSigSharesManager::CollectSigSharesToRequest -- timeout while waiting for %s-%d, node=%d\n", + LogPrint(BCLog::LLMQ, "CSigSharesManager::CollectSigSharesToRequest -- timeout while waiting for %s-%d, node=%d\n", k.first.ToString(), k.second, nodeId); return true; } @@ -843,7 +831,7 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_mapsecond >= SIG_SHARE_REQUEST_TIMEOUT && nodeId != p->first) { // other node timed out, re-request from this node - LogPrintf("llmq", "CSigSharesManager::%s -- other node timeout while waiting for %s-%d, re-request from=%d, node=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- other node timeout while waiting for %s-%d, re-request from=%d, node=%d\n", __func__, k.first.ToString(), k.second, nodeId, p->first); } else { continue; @@ -876,9 +864,10 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map>& sigSharesToSend) { + AssertLockHeld(cs); + for (auto& p : nodeStates) { auto nodeId = p.first; auto& nodeState = p.second; @@ -927,10 +916,11 @@ void CSigSharesManager::CollectSigSharesToSend(std::unordered_map>& sigSharesToAnnounce) { - std::unordered_set, StaticSaltedHasher> quorumNodesPrepared; + AssertLockHeld(cs); + + std::unordered_map, std::unordered_set, StaticSaltedHasher> quorumNodesMap; this->sigSharesToAnnounce.ForEach([&](const SigShareKey& sigShareKey, bool) { auto& signHash = sigShareKey.first; @@ -940,31 +930,20 @@ void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_mapllmqType, sigShare->quorumHash); - if (quorumNodesPrepared.emplace(quorumKey).second) { - // make sure we announce to at least the nodes which we know through the inter-quorum-communication system - + auto it = quorumNodesMap.find(quorumKey); + if (it == quorumNodesMap.end()) { auto nodeIds = g_connman->GetTierTwoConnMan()->getQuorumNodes(quorumKey.first, quorumKey.second); - for (auto nodeId : nodeIds) { - auto& nodeState = nodeStates[nodeId]; - nodeState.interestedIn.emplace(quorumKey); - } + it = quorumNodesMap.emplace(std::piecewise_construct, std::forward_as_tuple(quorumKey), std::forward_as_tuple(nodeIds.begin(), nodeIds.end())).first; } - for (auto& p : nodeStates) { - auto nodeId = p.first; - auto& nodeState = p.second; + auto& quorumNodes = it->second; - if (nodeState.banned) { - continue; - } + for (auto& nodeId : quorumNodes) { + auto& nodeState = nodeStates[nodeId]; - if (!nodeState.interestedIn.count(quorumKey)) { - // node is not interested in this sig share - // we only consider nodes to be interested if they sent us valid sig share before - // the sig share that we sign by ourself circumvents the inv system and is directly sent to all quorum members - // which are known by the deterministic inter-quorum-communication system. This is also the sig share that - // will tell the other nodes that we are interested in future sig shares + if (nodeState.banned) { continue; } @@ -986,9 +965,6 @@ void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_mapsigSharesToAnnounce.Clear(); } @@ -1048,7 +1024,9 @@ bool CSigSharesManager::SendMessages() bool didSend = false; - g_connman->ForEachNode([&](CNode* pnode) { + std::vector vNodesCopy = g_connman->CopyNodeVector(CConnman::FullyConnectedOnly); + + for (auto& pnode : vNodesCopy) { CNetMsgMaker msgMaker(pnode->GetSendVersion()); auto it1 = sigSessionAnnouncements.find(pnode->GetId()); @@ -1056,7 +1034,7 @@ bool CSigSharesManager::SendMessages() std::vector msgs; msgs.reserve(it1->second.size()); for (auto& sigSesAnn : it1->second) { - LogPrintf("llmq", "CSigSharesManager::SendMessages -- QSIGSESANN signHash=%s, sessionId=%d, node=%d\n", + LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QSIGSESANN signHash=%s, sessionId=%d, node=%d\n", llmq::utils::BuildSignHash(sigSesAnn).ToString(), sigSesAnn.sessionId, pnode->GetId()); msgs.emplace_back(sigSesAnn); if (msgs.size() == MAX_MSGS_CNT_QSIGSESANN) { @@ -1076,7 +1054,7 @@ bool CSigSharesManager::SendMessages() std::vector msgs; for (auto& p : it->second) { assert(p.second.CountSet() != 0); - LogPrintf("llmq", "CSigSharesManager::SendMessages -- QGETSIGSHARES signHash=%s, inv={%s}, node=%d\n", + LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QGETSIGSHARES signHash=%s, inv={%s}, node=%d\n", p.first.ToString(), p.second.ToString(), pnode->GetId()); msgs.emplace_back(std::move(p.second)); if (msgs.size() == MAX_MSGS_CNT_QGETSIGSHARES) { @@ -1119,7 +1097,7 @@ bool CSigSharesManager::SendMessages() std::vector msgs; for (auto& p : kt->second) { assert(p.second.CountSet() != 0); - LogPrintf("llmq", "CSigSharesManager::SendMessages -- QSIGSHARESINV signHash=%s, inv={%s}, node=%d\n", + LogPrint(BCLog::LLMQ, "CSigSharesManager::SendMessages -- QSIGSHARESINV signHash=%s, inv={%s}, node=%d\n", p.first.ToString(), p.second.ToString(), pnode->GetId()); msgs.emplace_back(std::move(p.second)); if (msgs.size() == MAX_MSGS_CNT_QSIGSHARESINV) { @@ -1133,9 +1111,10 @@ bool CSigSharesManager::SendMessages() didSend = true; } } + } - return true; - }); + // looped through all nodes, release them + g_connman->ReleaseNodeVector(vNodesCopy); return didSend; } @@ -1256,10 +1235,10 @@ void CSigSharesManager::Cleanup() } } - LogPrintf("CSigSharesManager::%s -- signing session timed out. signHash=%s, id=%s, msgHash=%s, sigShareCount=%d, missingMembers=%s\n", __func__, - signHash.ToString(), oneSigShare.id.ToString(), oneSigShare.msgHash.ToString(), count, strMissingMembers); + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signing session timed out. signHash=%s, id=%s, msgHash=%s, sigShareCount=%d, missingMembers=%s\n", __func__, + signHash.ToString(), oneSigShare.id.ToString(), oneSigShare.msgHash.ToString(), count, strMissingMembers); } else { - LogPrintf("CSigSharesManager::%s -- signing session timed out. signHash=%s, sigShareCount=%d\n", __func__, + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signing session timed out. signHash=%s, sigShareCount=%d\n", __func__, signHash.ToString(), count); } RemoveSigSharesForSession(signHash); @@ -1407,7 +1386,7 @@ void CSigSharesManager::Sign(const CQuorumCPtr& quorum, const uint256& id, const CBLSSecretKey skShare = quorum->GetSkShare(); if (!skShare.IsValid()) { - LogPrintf("CSigSharesManager::%s -- we don't have our skShare for quorum %s\n", __func__, quorum->pindexQuorum->GetBlockHash().ToString()); + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- we don't have our skShare for quorum %s\n", __func__, quorum->pindexQuorum->GetBlockHash().ToString()); return; } @@ -1434,7 +1413,7 @@ void CSigSharesManager::Sign(const CQuorumCPtr& quorum, const uint256& id, const sigShare.UpdateKey(); - LogPrintf("CSigSharesManager::%s -- signed sigShare. signHash=%s, id=%s, msgHash=%s, time=%s\n", __func__, + LogPrint(BCLog::LLMQ, "CSigSharesManager::%s -- signed sigShare. signHash=%s, id=%s, msgHash=%s, time=%s\n", __func__, signHash.ToString(), sigShare.id.ToString(), sigShare.msgHash.ToString(), t.count()); ProcessSigShare(-1, sigShare, *g_connman, quorum); } @@ -1445,4 +1424,4 @@ void CSigSharesManager::HandleNewRecoveredSig(const llmq::CRecoveredSig& recover RemoveSigSharesForSession(llmq::utils::BuildSignHash(recoveredSig)); } -} // namespace llmq \ No newline at end of file +} // namespace llmq diff --git a/src/llmq/quorums_signing_shares.h b/src/llmq/quorums_signing_shares.h index 28d73fb9a99bb..ccad1312386b3 100644 --- a/src/llmq/quorums_signing_shares.h +++ b/src/llmq/quorums_signing_shares.h @@ -308,10 +308,6 @@ class CSigSharesNodeState SigShareMap pendingIncomingSigShares; SigShareMap requestedSigShares; - // elements are added whenever we receive a valid sig share from this node - // this triggers us to send inventory items to him as he seems to be interested in these - std::unordered_set, StaticSaltedHasher> interestedIn; - bool banned{false}; Session& GetOrCreateSessionFromShare(const CSigShare& sigShare); diff --git a/src/logging.cpp b/src/logging.cpp index 932155f5e14e0..c80485427227a 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -125,6 +125,7 @@ const CLogCategoryDesc LogCategories[] = { {BCLog::LLMQ, "llmq"}, {BCLog::NET_MN, "net_mn"}, {BCLog::DKG, "dkg"}, + {BCLog::CHAINLOCKS, "chainlocks"}, {BCLog::ALL, "1"}, {BCLog::ALL, "all"}, }; diff --git a/src/logging.h b/src/logging.h index 3249d6dd8531e..169f2edeb944e 100644 --- a/src/logging.h +++ b/src/logging.h @@ -66,6 +66,7 @@ namespace BCLog { LLMQ = (1 << 25), NET_MN = (1 << 26), DKG = (1 << 27), + CHAINLOCKS = (1 << 28), ALL = ~(uint32_t)0, }; diff --git a/src/net.cpp b/src/net.cpp index df99e2954a950..ee4dafe96f4c6 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -1434,13 +1434,8 @@ void CConnman::SocketHandler() // // Service each socket // - std::vector vNodesCopy; - { - LOCK(cs_vNodes); - vNodesCopy = vNodes; - for (CNode* pnode : vNodesCopy) - pnode->AddRef(); - } + std::vector vNodesCopy = CopyNodeVector(); + for (CNode* pnode : vNodesCopy) { if (interruptNet) return; @@ -1518,11 +1513,7 @@ void CConnman::SocketHandler() InactivityCheck(pnode); } - { - LOCK(cs_vNodes); - for (CNode* pnode : vNodesCopy) - pnode->Release(); - } + ReleaseNodeVector(vNodesCopy); } void CConnman::ThreadSocketHandler() @@ -1947,14 +1938,7 @@ void CConnman::ThreadMessageHandler() int64_t nLastSendMessagesTimeMasternodes = 0; while (!flagInterruptMsgProc) { - std::vector vNodesCopy; - { - LOCK(cs_vNodes); - vNodesCopy = vNodes; - for (CNode* pnode : vNodesCopy) { - pnode->AddRef(); - } - } + std::vector vNodesCopy = CopyNodeVector(); bool fMoreWork = false; @@ -1986,11 +1970,7 @@ void CConnman::ThreadMessageHandler() } - { - LOCK(cs_vNodes); - for (CNode* pnode : vNodesCopy) - pnode->Release(); - } + ReleaseNodeVector(vNodesCopy); std::unique_lock lock(mutexMsgProc); if (!fMoreWork) { @@ -2791,6 +2771,33 @@ int64_t PoissonNextSend(int64_t nNow, int average_interval_seconds) { return nNow + (int64_t)(log1p(GetRand(1ULL << 48) * -0.0000000000000035527136788 /* -1/2^48 */) * average_interval_seconds * -1000000.0 + 0.5); } +std::vector CConnman::CopyNodeVector(std::function cond) +{ + std::vector vecNodesCopy; + LOCK(cs_vNodes); + for (size_t i = 0; i < vNodes.size(); ++i) { + CNode* pnode = vNodes[i]; + if (!cond(pnode)) + continue; + pnode->AddRef(); + vecNodesCopy.push_back(pnode); + } + return vecNodesCopy; +} + +std::vector CConnman::CopyNodeVector() +{ + return CopyNodeVector(AllNodes); +} + +void CConnman::ReleaseNodeVector(const std::vector& vecNodes) +{ + for (size_t i = 0; i < vecNodes.size(); ++i) { + CNode* pnode = vecNodes[i]; + pnode->Release(); + } +} + CSipHasher CConnman::GetDeterministicRandomizer(uint64_t id) { return CSipHasher(nSeed0, nSeed1).Write(id); diff --git a/src/net.h b/src/net.h index 86ec239dae685..581321f36633a 100644 --- a/src/net.h +++ b/src/net.h @@ -280,6 +280,10 @@ class CConnman post(); }; + std::vector CopyNodeVector(std::function cond); + std::vector CopyNodeVector(); + void ReleaseNodeVector(const std::vector& vecNodes); + // Clears AskFor requests for every known peer void RemoveAskFor(const uint256& invHash, int invType); diff --git a/src/rpc/rpcquorums.cpp b/src/rpc/rpcquorums.cpp index e0cd374f03744..c1a688325c30b 100644 --- a/src/rpc/rpcquorums.cpp +++ b/src/rpc/rpcquorums.cpp @@ -207,8 +207,8 @@ UniValue getquoruminfo(const JSONRPCRequest& request) auto& dmn = quorum->members[i]; UniValue mo(UniValue::VOBJ); mo.pushKV("proTxHash", dmn->proTxHash.ToString()); - mo.pushKV("valid", quorum->validMembers[i]); - if (quorum->validMembers[i]) { + mo.pushKV("valid", quorum->qc.validMembers[i]); + if (quorum->qc.validMembers[i]) { CBLSPublicKey pubKey = quorum->GetPubKeyShare(i); if (pubKey.IsValid()) { mo.pushKV("pubKeyShare", pubKey.ToString()); @@ -218,7 +218,7 @@ UniValue getquoruminfo(const JSONRPCRequest& request) } ret.pushKV("members", membersArr); - ret.pushKV("quorumPublicKey", quorum->quorumPublicKey.ToString()); + ret.pushKV("quorumPublicKey", quorum->qc.quorumPublicKey.ToString()); CBLSSecretKey skShare = quorum->GetSkShare(); if (includeSkShare && skShare.IsValid()) { ret.pushKV("secretKeyShare", skShare.ToString()); diff --git a/test/functional/tiertwo_chainlocks.py b/test/functional/tiertwo_chainlocks.py index 1fab530eda18d..5633b485fd1e4 100755 --- a/test/functional/tiertwo_chainlocks.py +++ b/test/functional/tiertwo_chainlocks.py @@ -80,11 +80,11 @@ def run_test(self): # Keep node connected and let it try to reorg the chain good_tip = self.nodes[0].getbestblockhash() - self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) # Restart it so that it forgets all the chainlocks from the past self.stop_node(0) self.start_node(0, extra_args=self.extra_args[0]) connect_nodes(self.nodes[0], 1) + self.nodes[0].invalidateblock(self.nodes[0].getbestblockhash()) # Now try to reorg the chain self.nodes[0].generate(2) time.sleep(2) diff --git a/test/functional/tiertwo_signing_session.py b/test/functional/tiertwo_signing_session.py index adb2279fe0ba7..1496ac6bf2989 100755 --- a/test/functional/tiertwo_signing_session.py +++ b/test/functional/tiertwo_signing_session.py @@ -60,11 +60,11 @@ def run_test(self): # At this point a recovery threshold signature should have been generated and propagated to the whole network # Let's generate some blocks to ensure that nodes are synced time.sleep(5) - for i in range(len(self.nodes)): + for i in [m.idx for m in members]: assert_equal(True, self.nodes[i].hasrecoverysignature(100, id, msgHash)) # Moreover since we have a recovery signature we surely cannot sign a message with the same id - for i in range(len(self.nodes)): + for i in [m.idx for m in members]: assert_equal(False, self.nodes[i].hasrecoverysignature(100, id, msgHashConflict)) self.log.info("Threshold signature successfully generated and propagated!") @@ -93,7 +93,7 @@ def run_test(self): # Since with this quorum type 2 nodes are enough to generate the threshold signature at the end every node MUST agree on (id, msgHash) # Let's wait a bit to sync all messages time.sleep(5) - for i in range(len(self.nodes)): + for i in [m.idx for m in members]: assert_equal(True, self.nodes[i].hasrecoverysignature(100, id, msgHash)) self.log.info("Threshold signature successfully generated and propagated!") @@ -102,7 +102,7 @@ def run_test(self): self.mine_quorum() self.mine_quorum() time.sleep(5) - for i in range(len(self.nodes)): + for i in [m.idx for m in members]: assert_equal(True, self.nodes[i].hasrecoverysignature(100, id, msgHash)) self.log.info("Threshold signature is still valid after the corresponding quorum went inactive!")