Skip to content

Commit

Permalink
Speed up CQuorumManager::ScanQuorums (#2677)
Browse files Browse the repository at this point in the history
* Store quorumHash of first mined commitment in evoDb

This allows to skip scanning for quorums below this block.

* Speed up CQuorumManager::ScanQuorums

This does 2 things:
1. Only call HasQuorum for blocks that are potentially a quorumBlockHash
   These are only blocks which are at index 0 of each DKG interval
2. Stop scanning for quorums when we get below the first block that
   contained a commitment. If no commitment was ever mined, we bail out
   immediately.

* Return result instead of {}

* Remove HasQuorum() call as GetQuorum already does this

* Remove unnecessary "if (!qc.IsNull()))"

It's already checked at the top of the loop

* When necessary, remove DB_FIRST_MINED_COMMITMENT from evoDb in UndoBlock
  • Loading branch information
codablock authored and UdjinM6 committed Feb 2, 2019
1 parent 3175526 commit 03fa115
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 13 deletions.
33 changes: 23 additions & 10 deletions src/llmq/quorums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,26 +308,39 @@ std::vector<CQuorumCPtr> CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp
std::vector<CQuorumCPtr> CQuorumManager::ScanQuorums(Consensus::LLMQType llmqType, const uint256& startBlock, size_t maxCount)
{
std::vector<CQuorumCPtr> result;
result.reserve(maxCount);

auto& params = Params().GetConsensus().llmqs.at(llmqType);

auto firstQuorumHash = quorumBlockProcessor->GetFirstMinedQuorumHash(llmqType);
if (firstQuorumHash.IsNull()) {
// no quorum mined yet, avoid scanning the whole chain down to genesis
return result;
}

LOCK(cs_main);
if (!mapBlockIndex.count(startBlock)) {
return result;
}

result.reserve(maxCount);

CBlockIndex* pindex = mapBlockIndex[startBlock];
pindex = chainActive[pindex->nHeight - (pindex->nHeight % params.dkgInterval)];

while (pindex != nullptr
&& pindex->nHeight >= params.dkgInterval
&& result.size() < maxCount
&& deterministicMNManager->IsDIP3Enforced(pindex->nHeight)) {
auto quorum = GetQuorum(llmqType, pindex->GetBlockHash());
if (quorum) {
result.emplace_back(quorum);
}

while (pindex != NULL && result.size() < maxCount && deterministicMNManager->IsDIP3Enforced(pindex->nHeight)) {
if (HasQuorum(llmqType, pindex->GetBlockHash())) {
auto quorum = GetQuorum(llmqType, pindex->GetBlockHash());
if (quorum) {
result.emplace_back(quorum);
}
if (pindex->GetBlockHash() == firstQuorumHash) {
// no need to scan further if we know that there are no quorums below this block
break;
}

// TODO speedup (skip blocks where no quorums could have been mined)
pindex = pindex->pprev;
pindex = pindex->GetAncestor(pindex->nHeight - params.dkgInterval);
}

return result;
Expand Down
23 changes: 20 additions & 3 deletions src/llmq/quorums_blockprocessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace llmq
CQuorumBlockProcessor* quorumBlockProcessor;

static const std::string DB_MINED_COMMITMENT = "q_mc";
static const std::string DB_FIRST_MINED_COMMITMENT = "q_fmc";

void CQuorumBlockProcessor::ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStream& vRecv, CConnman& connman)
{
Expand Down Expand Up @@ -188,6 +189,9 @@ bool CQuorumBlockProcessor::ProcessCommitment(const CBlockIndex* pindex, const C

// Store commitment in DB
evoDb.Write(std::make_pair(DB_MINED_COMMITMENT, std::make_pair((uint8_t)params.type, quorumHash)), qc);
if (!evoDb.Exists(std::make_pair(DB_FIRST_MINED_COMMITMENT, (uint8_t)params.type))) {
evoDb.Write(std::make_pair(DB_FIRST_MINED_COMMITMENT, (uint8_t)params.type), quorumHash);
}

LogPrintf("CQuorumBlockProcessor::%s -- processed commitment from block. type=%d, quorumHash=%s, signers=%s, validMembers=%d, quorumPublicKey=%s\n", __func__,
qc.llmqType, quorumHash.ToString(), qc.CountSigners(), qc.CountValidMembers(), qc.quorumPublicKey.ToString());
Expand All @@ -213,9 +217,12 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pi

evoDb.Erase(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(qc.llmqType, qc.quorumHash)));

if (!qc.IsNull()) {
// if a reorg happened, we should allow to mine this commitment later
AddMinableCommitment(qc);
// if a reorg happened, we should allow to mine this commitment later
AddMinableCommitment(qc);

uint256 fmq = GetFirstMinedQuorumHash(p.first);
if (fmq == qc.quorumHash) {
evoDb.Erase(std::make_pair(DB_FIRST_MINED_COMMITMENT, (uint8_t)p.first));
}
}

Expand Down Expand Up @@ -306,6 +313,16 @@ bool CQuorumBlockProcessor::GetMinedCommitment(Consensus::LLMQType llmqType, con
return evoDb.Read(key, ret);
}

uint256 CQuorumBlockProcessor::GetFirstMinedQuorumHash(Consensus::LLMQType llmqType)
{
auto key = std::make_pair(DB_FIRST_MINED_COMMITMENT, (uint8_t)llmqType);
uint256 quorumHash;
if (!evoDb.Read(key, quorumHash)) {
return uint256();
}
return quorumHash;
}

bool CQuorumBlockProcessor::HasMinableCommitment(const uint256& hash)
{
LOCK(minableCommitmentsCs);
Expand Down
2 changes: 2 additions & 0 deletions src/llmq/quorums_blockprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class CQuorumBlockProcessor
bool HasMinedCommitment(Consensus::LLMQType llmqType, const uint256& quorumHash);
bool GetMinedCommitment(Consensus::LLMQType llmqType, const uint256& quorumHash, CFinalCommitment& ret);

uint256 GetFirstMinedQuorumHash(Consensus::LLMQType llmqType);

private:
bool GetCommitmentsFromBlock(const CBlock& block, const CBlockIndex* pindexPrev, std::map<Consensus::LLMQType, CFinalCommitment>& ret, CValidationState& state);
bool ProcessCommitment(const CBlockIndex* pindex, const CFinalCommitment& qc, CValidationState& state);
Expand Down

0 comments on commit 03fa115

Please sign in to comment.