Skip to content

Commit

Permalink
Implement GetMined(AndActive)CommitmentsUntilBlock and use it in Scan…
Browse files Browse the repository at this point in the history
…Quorums

This fixes a bug in ScanQuorums which made it return quorums which were not
mined at the time of pindexStart. This was due to quorumHashes being based
on older blocks (the phase=0 block) which are ancestors of pindexStart even
if the commitment was actually mined in a later block.

GetMinedAndActiveCommitmentsUntilBlock is also going to be used for quorum
commitment merkle roots in CCbTx.

This also removes GetFirstMinedQuorumHash as it's not needed anymore.
  • Loading branch information
codablock committed Apr 4, 2019
1 parent d5250a3 commit 0762074
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 37 deletions.
5 changes: 5 additions & 0 deletions src/evo/evodb.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ class CEvoDB
return t;
}

CurTransaction& GetCurTransaction()
{
return curDBTransaction;
}

template <typename K, typename V>
bool Read(const K& key, V& value)
{
Expand Down
32 changes: 8 additions & 24 deletions src/llmq/quorums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -300,34 +300,18 @@ std::vector<CQuorumCPtr> CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp

std::vector<CQuorumCPtr> CQuorumManager::ScanQuorums(Consensus::LLMQType llmqType, const CBlockIndex* pindexStart, 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;
}

auto pindex = pindexStart->GetAncestor(pindexStart->nHeight - (pindexStart->nHeight % params.dkgInterval));
auto quorumIndexes = quorumBlockProcessor->GetMinedCommitmentsUntilBlock(params.type, pindexStart, maxCount);

while (pindex != nullptr
&& pindex->nHeight >= params.dkgInterval
&& result.size() < maxCount
&& deterministicMNManager->IsDIP3Enforced(pindex->nHeight)) {
auto quorum = GetQuorum(llmqType, pindex);
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;
}
std::vector<CQuorumCPtr> result;
result.reserve(quorumIndexes.size());

pindex = pindex->GetAncestor(pindex->nHeight - params.dkgInterval);
for (auto& quorumIndex : quorumIndexes) {
assert(quorumIndex);
auto quorum = GetQuorum(params.type, quorumIndex);
assert(quorum != nullptr);
result.emplace_back(quorum);
}

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

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

static const std::string DB_UPGRADED = "q_dbupgraded";
Expand Down Expand Up @@ -244,11 +243,6 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pi

// 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));
}
}

return true;
Expand Down Expand Up @@ -392,14 +386,61 @@ bool CQuorumBlockProcessor::GetMinedCommitment(Consensus::LLMQType llmqType, con
return evoDb.Read(key, ret);
}

uint256 CQuorumBlockProcessor::GetFirstMinedQuorumHash(Consensus::LLMQType llmqType)
std::vector<const CBlockIndex*> CQuorumBlockProcessor::GetMinedCommitmentsUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t maxCount)
{
auto key = std::make_pair(DB_FIRST_MINED_COMMITMENT, (uint8_t)llmqType);
uint256 quorumHash;
if (!evoDb.Read(key, quorumHash)) {
return uint256();
auto dbIt = evoDb.GetCurTransaction().NewIteratorUniquePtr();

auto firstKey = BuildInversedHeightKey(llmqType, pindex->nHeight);
auto lastKey = BuildInversedHeightKey(llmqType, 0);

dbIt->Seek(firstKey);

std::vector<const CBlockIndex*> ret;
ret.reserve(maxCount);

while (dbIt->Valid() && ret.size() < maxCount) {
decltype(firstKey) curKey;
int quorumHeight;
if (!dbIt->GetKey(curKey) || curKey >= lastKey) {
break;
}
if (std::get<0>(curKey) != DB_MINED_COMMITMENT_BY_INVERSED_HEIGHT || std::get<1>(curKey) != (uint8_t)llmqType) {
break;
}

int nMinedHeight = std::numeric_limits<int>::max() - std::get<2>(curKey);
if (nMinedHeight > pindex->nHeight) {
break;
}

if (!dbIt->GetValue(quorumHeight)) {
break;
}

auto quorumIndex = pindex->GetAncestor(quorumHeight);
assert(quorumIndex);
ret.emplace_back(pindex->GetAncestor(quorumHeight));

dbIt->Next();
}
return quorumHash;

return ret;
}

std::map<Consensus::LLMQType, std::vector<const CBlockIndex*>> CQuorumBlockProcessor::GetMinedAndActiveCommitmentsUntilBlock(const CBlockIndex* pindex)
{
std::map<Consensus::LLMQType, std::vector<const CBlockIndex*>> ret;

for (const auto& p : Params().GetConsensus().llmqs) {
auto& v = ret[p.second.type];
v.reserve(p.second.signingActiveQuorumCount);
auto commitments = GetMinedCommitmentsUntilBlock(p.second.type, pindex, p.second.signingActiveQuorumCount);
for (auto& c : commitments) {
v.emplace_back(c);
}
}

return ret;
}

bool CQuorumBlockProcessor::HasMinableCommitment(const uint256& hash)
Expand Down
3 changes: 2 additions & 1 deletion src/llmq/quorums_blockprocessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,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);
std::vector<const CBlockIndex*> GetMinedCommitmentsUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t maxCount);
std::map<Consensus::LLMQType, std::vector<const CBlockIndex*>> GetMinedAndActiveCommitmentsUntilBlock(const CBlockIndex* pindex);

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

0 comments on commit 0762074

Please sign in to comment.