Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: trim and document assumptions for GetQuorum, Get*MN* and friends #6132

Draft
wants to merge 2 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/evo/assetlocktx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,10 @@ bool CAssetUnlockPayload::VerifySig(const llmq::CQuorumManager& qman, const uint
}

const auto quorum = qman.GetQuorum(llmqType, quorumHash);
assert(quorum);
if (quorum == nullptr) {
LogPrint(BCLog::CREDITPOOL, "No quorum for found for hash=%s\n", quorumHash.ToString());
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-assetunlock-missing-quorum");
}

const uint256 requestId = ::SerializeHash(std::make_pair(ASSETUNLOCK_REQUESTID_PREFIX, index));

Expand Down
16 changes: 12 additions & 4 deletions src/evo/deterministicmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ CDeterministicMNList CDeterministicMNList::ApplyDiff(gsl::not_null<const CBlockI
for (const auto& id : diff.removedMns) {
auto dmn = result.GetMNByInternalId(id);
if (!dmn) {
throw(std::runtime_error(strprintf("%s: can't find a removed masternode, id=%d", __func__, id)));
throw std::runtime_error(strprintf("%s: can't find a removed masternode, id=%d", __func__, id));
}
result.RemoveMN(dmn->proTxHash);
}
Expand All @@ -435,6 +435,9 @@ CDeterministicMNList CDeterministicMNList::ApplyDiff(gsl::not_null<const CBlockI
}
for (const auto& p : diff.updatedMNs) {
auto dmn = result.GetMNByInternalId(p.first);
if (!dmn) {
throw std::runtime_error(strprintf("%s: can't find an updated masternode, id=%d", __func__, p.first));
}
result.UpdateMN(*dmn, p.second);
}

Expand Down Expand Up @@ -816,7 +819,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-dup-addr");
}

CDeterministicMNCPtr dmn = newList.GetMN(opt_proTx->proTxHash);
auto dmn = newList.GetMN(opt_proTx->proTxHash);
if (!dmn) {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash");
}
Expand Down Expand Up @@ -857,7 +860,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
}

CDeterministicMNCPtr dmn = newList.GetMN(opt_proTx->proTxHash);
auto dmn = newList.GetMN(opt_proTx->proTxHash);
if (!dmn) {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash");
}
Expand Down Expand Up @@ -885,7 +888,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-payload");
}

CDeterministicMNCPtr dmn = newList.GetMN(opt_proTx->proTxHash);
auto dmn = newList.GetMN(opt_proTx->proTxHash);
if (!dmn) {
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-protx-hash");
}
Expand Down Expand Up @@ -945,6 +948,8 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
// current block. We still pay that MN one last time, however.
if (payee && newList.HasMN(payee->proTxHash)) {
auto dmn = newList.GetMN(payee->proTxHash);
// HasMN has reported that GetMN should succeed, enforce that.
assert(dmn);
auto newState = std::make_shared<CDeterministicMNState>(*dmn->pdmnState);
newState->nLastPaidHeight = nHeight;
// Starting from v19 and until MNRewardReallocation, EvoNodes will be paid 4 blocks in a row
Expand All @@ -960,6 +965,9 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no
newList.UpdateMN(payee->proTxHash, newState);
if (debugLogs) {
dmn = newList.GetMN(payee->proTxHash);
// Since the previous GetMN query returned a value, after an update, querying the same
// hash *must* give us a result. If it doesn't, that would be a potential logic bug.
assert(dmn);
LogPrint(BCLog::MNPAYMENTS, "CDeterministicMNManager::%s -- MN %s, nConsecutivePayments=%d\n",
__func__, dmn->proTxHash.ToString(), dmn->pdmnState->nConsecutivePayments);
}
Expand Down
4 changes: 4 additions & 0 deletions src/evo/mnhftx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ bool MNHFTx::Verify(const llmq::CQuorumManager& qman, const uint256& quorumHash,
const Consensus::LLMQType& llmqType = Params().GetConsensus().llmqTypeMnhf;
const auto quorum = qman.GetQuorum(llmqType, quorumHash);

if (quorum == nullptr) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-missing-quorum");
}

const uint256 signHash = llmq::BuildSignHash(llmqType, quorum->qc->quorumHash, requestId, msgHash);
if (!sig.VerifyInsecure(quorum->qc->quorumPublicKey, signHash)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-invalid");
Expand Down
20 changes: 17 additions & 3 deletions src/evo/simplifiedmns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,23 @@ bool CSimplifiedMNListDiff::BuildQuorumsDiff(const CBlockIndex* baseBlockIndex,
return true;
}

void CSimplifiedMNListDiff::BuildQuorumChainlockInfo(const llmq::CQuorumManager& qman, const CBlockIndex* blockIndex)
bool CSimplifiedMNListDiff::BuildQuorumChainlockInfo(const llmq::CQuorumManager& qman, const CBlockIndex* blockIndex)
{
// Group quorums (indexes corresponding to entries of newQuorums) per CBlockIndex containing the expected CL signature in CbTx.
// We want to avoid to load CbTx now, as more than one quorum will target the same block: hence we want to load CbTxs once per block (heavy operation).
std::multimap<const CBlockIndex*, uint16_t> workBaseBlockIndexMap;

for (const auto [idx, e] : enumerate(newQuorums)) {
// We assume that we have on hand, quorums that correspond to the hashes queried.
// If we cannot find them, something must have gone wrong and we should cease trying
// to build any further.
auto quorum = qman.GetQuorum(e.llmqType, e.quorumHash);
if (quorum == nullptr) {
LogPrintf("%s: ERROR! Unexpected missing quorum with llmqType=%d, quorumHash=%s\n", __func__,
ToUnderlying(e.llmqType), e.quorumHash.ToString());
return false;
kwvg marked this conversation as resolved.
Show resolved Hide resolved
}

// In case of rotation, all rotated quorums rely on the CL sig expected in the cycleBlock (the block of the first DKG) - 8
// In case of non-rotation, quorums rely on the CL sig expected in the block of the DKG - 8
const CBlockIndex* pWorkBaseBlockIndex =
Expand All @@ -199,7 +208,7 @@ void CSimplifiedMNListDiff::BuildQuorumChainlockInfo(const llmq::CQuorumManager&
workBaseBlockIndexMap.insert(std::make_pair(pWorkBaseBlockIndex, idx));
}

for(auto it = workBaseBlockIndexMap.begin(); it != workBaseBlockIndexMap.end(); ) {
for (auto it = workBaseBlockIndexMap.begin(); it != workBaseBlockIndexMap.end();) {
// Process each key (CBlockIndex containing the expected CL signature in CbTx) of the std::multimap once
const CBlockIndex* pWorkBaseBlockIndex = it->first;
const auto cbcl = GetNonNullCoinbaseChainlock(pWorkBaseBlockIndex);
Expand All @@ -220,6 +229,8 @@ void CSimplifiedMNListDiff::BuildQuorumChainlockInfo(const llmq::CQuorumManager&
it_sig->second.insert(idx_set.begin(), idx_set.end());
}
}

return true;
}

UniValue CSimplifiedMNListDiff::ToJson(bool extended) const
Expand Down Expand Up @@ -362,7 +373,10 @@ bool BuildSimplifiedMNListDiff(CDeterministicMNManager& dmnman, const Chainstate
}

if (DeploymentActiveAfter(blockIndex, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) {
mnListDiffRet.BuildQuorumChainlockInfo(qman, blockIndex);
if (!mnListDiffRet.BuildQuorumChainlockInfo(qman, blockIndex)) {
errorRet = strprintf("failed to build quorum chainlock info");
return false;
}
}

// TODO store coinbase TX in CBlockIndex
Expand Down
2 changes: 1 addition & 1 deletion src/evo/simplifiedmns.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ class CSimplifiedMNListDiff

bool BuildQuorumsDiff(const CBlockIndex* baseBlockIndex, const CBlockIndex* blockIndex,
const llmq::CQuorumBlockProcessor& quorum_block_processor);
void BuildQuorumChainlockInfo(const llmq::CQuorumManager& qman, const CBlockIndex* blockIndex);
bool BuildQuorumChainlockInfo(const llmq::CQuorumManager& qman, const CBlockIndex* blockIndex);

[[nodiscard]] UniValue ToJson(bool extended = false) const;
};
Expand Down
6 changes: 6 additions & 0 deletions src/governance/governance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1559,6 +1559,9 @@ void CGovernanceManager::RemoveInvalidVotes()
std::vector<COutPoint> changedKeyMNs;
for (const auto& p : diff.updatedMNs) {
auto oldDmn = lastMNListForVotingKeys->GetMNByInternalId(p.first);
// BuildDiff will construct itself with MNs that we already have knowledge
// of, meaning that fetch operations should never fail.
assert(oldDmn);
if ((p.second.fields & CDeterministicMNStateDiff::Field_keyIDVoting) && p.second.state.keyIDVoting != oldDmn->pdmnState->keyIDVoting) {
changedKeyMNs.emplace_back(oldDmn->collateralOutpoint);
} else if ((p.second.fields & CDeterministicMNStateDiff::Field_pubKeyOperator) && p.second.state.pubKeyOperator != oldDmn->pdmnState->pubKeyOperator) {
Expand All @@ -1567,6 +1570,9 @@ void CGovernanceManager::RemoveInvalidVotes()
}
for (const auto& id : diff.removedMns) {
auto oldDmn = lastMNListForVotingKeys->GetMNByInternalId(id);
// BuildDiff will construct itself with MNs that we already have knowledge
// of, meaning that fetch operations should never fail.
assert(oldDmn);
changedKeyMNs.emplace_back(oldDmn->collateralOutpoint);
}

Expand Down
13 changes: 11 additions & 2 deletions src/llmq/quorums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,8 +594,17 @@ std::vector<CQuorumCPtr> CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp
assert(pQuorumBaseBlockIndex);
// populate cache for keepOldConnections most recent quorums only
bool populate_cache = vecResultQuorums.size() < static_cast<size_t>(llmq_params_opt->keepOldConnections);

// We assume that every quorum asked for is available to us on hand, if this
// fails then we can assume that something has gone wrong and we should stop
// trying to process any further and return a blank.
auto quorum = GetQuorum(llmqType, pQuorumBaseBlockIndex, populate_cache);
assert(quorum != nullptr);
if (quorum == nullptr) {
LogPrintf("%s: ERROR! Unexpected missing quorum with llmqType=%d, blockHash=%s, populate_cache=%s\n",
__func__, ToUnderlying(llmqType), pQuorumBaseBlockIndex->GetBlockHash().ToString(),
populate_cache ? "true" : "false");
return {};
kwvg marked this conversation as resolved.
Show resolved Hide resolved
}
vecResultQuorums.emplace_back(quorum);
}

Expand Down Expand Up @@ -734,7 +743,7 @@ PeerMsgRet CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_t
return sendQDATA(CQuorumDataRequest::Errors::QUORUM_BLOCK_NOT_FOUND, request_limit_exceeded);
}

const CQuorumCPtr pQuorum = GetQuorum(request.GetLLMQType(), pQuorumBaseBlockIndex);
const auto pQuorum = GetQuorum(request.GetLLMQType(), pQuorumBaseBlockIndex);
if (pQuorum == nullptr) {
return sendQDATA(CQuorumDataRequest::Errors::QUORUM_NOT_FOUND, request_limit_exceeded);
}
Expand Down
6 changes: 3 additions & 3 deletions src/llmq/signing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,7 +588,7 @@ static bool PreVerifyRecoveredSig(const CQuorumManager& quorum_manager, const CR
return false;
}

CQuorumCPtr quorum = quorum_manager.GetQuorum(llmqType, recoveredSig.getQuorumHash());
auto quorum = quorum_manager.GetQuorum(llmqType, recoveredSig.getQuorumHash());

if (!quorum) {
LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not found\n", __func__,
Expand Down Expand Up @@ -683,7 +683,7 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify(
auto llmqType = recSig->getLlmqType();
auto quorumKey = std::make_pair(recSig->getLlmqType(), recSig->getQuorumHash());
if (!retQuorums.count(quorumKey)) {
CQuorumCPtr quorum = qman.GetQuorum(llmqType, recSig->getQuorumHash());
auto quorum = qman.GetQuorum(llmqType, recSig->getQuorumHash());
if (!quorum) {
LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not found, node=%d\n", __func__,
recSig->getQuorumHash().ToString(), nodeId);
Expand Down Expand Up @@ -881,7 +881,7 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, CSigShares
if (m_mn_activeman == nullptr) return false;
if (m_mn_activeman->GetProTxHash().IsNull()) return false;

const CQuorumCPtr quorum = [&]() {
const auto quorum = [&]() {
if (quorumHash.IsNull()) {
// This might end up giving different results on different members
// This might happen when we are on the brink of confirming a new quorum
Expand Down
39 changes: 25 additions & 14 deletions src/llmq/signing_shares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -549,15 +549,14 @@ bool CSigSharesManager::PreVerifyBatchedSigShares(const CActiveMasternodeManager
return true;
}

void CSigSharesManager::CollectPendingSigSharesToVerify(
size_t maxUniqueSessions,
std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums)
bool CSigSharesManager::CollectPendingSigSharesToVerify(
size_t maxUniqueSessions, std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums)
{
{
LOCK(cs);
if (nodeStates.empty()) {
return;
return false;
}

// This will iterate node states in random order and pick one sig share at a time. This avoids processing
Expand Down Expand Up @@ -585,7 +584,7 @@ void CSigSharesManager::CollectPendingSigSharesToVerify(
}, rnd);

if (retSigShares.empty()) {
return;
return false;
}
}

Expand All @@ -600,11 +599,20 @@ void CSigSharesManager::CollectPendingSigSharesToVerify(
continue;
}

CQuorumCPtr quorum = qman.GetQuorum(llmqType, sigShare.getQuorumHash());
assert(quorum != nullptr);
auto quorum = qman.GetQuorum(llmqType, sigShare.getQuorumHash());
// Despite constructing a convenience map, we assume that the quorum *must* be present.
// The absence of it might indicate an inconsistent internal state, so we should report
// nothing instead of reporting flawed data.
if (quorum == nullptr) {
LogPrintf("%s: ERROR! Unexpected missing quorum with llmqType=%d, quorumHash=%s\n", __func__,
ToUnderlying(llmqType), sigShare.getQuorumHash().ToString());
return false;
}
retQuorums.try_emplace(k, quorum);
}
}

return true;
}

bool CSigSharesManager::ProcessPendingSigShares(const CConnman& connman)
Expand All @@ -613,8 +621,8 @@ bool CSigSharesManager::ProcessPendingSigShares(const CConnman& connman)
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher> quorums;

const size_t nMaxBatchSize{32};
CollectPendingSigSharesToVerify(nMaxBatchSize, sigSharesByNodes, quorums);
if (sigSharesByNodes.empty()) {
bool collect_status = CollectPendingSigSharesToVerify(nMaxBatchSize, sigSharesByNodes, quorums);
if (!collect_status || sigSharesByNodes.empty()) {
return false;
}

Expand Down Expand Up @@ -1261,11 +1269,14 @@ void CSigSharesManager::Cleanup()
// Find quorums which became inactive
for (auto it = quorums.begin(); it != quorums.end(); ) {
if (IsQuorumActive(it->first.first, qman, it->first.second)) {
it->second = qman.GetQuorum(it->first.first, it->first.second);
++it;
} else {
it = quorums.erase(it);
auto quorum = qman.GetQuorum(it->first.first, it->first.second);
if (quorum != nullptr) {
it->second = quorum;
++it;
continue;
}
}
it = quorums.erase(it);
}

{
Expand Down
6 changes: 3 additions & 3 deletions src/llmq/signing_shares.h
Original file line number Diff line number Diff line change
Expand Up @@ -448,9 +448,9 @@ class CSigSharesManager : public CRecoveredSigsListener
static bool PreVerifyBatchedSigShares(const CActiveMasternodeManager& mn_activeman, const CQuorumManager& quorum_manager,
const CSigSharesNodeState::SessionInfo& session, const CBatchedSigShares& batchedSigShares, bool& retBan);

void CollectPendingSigSharesToVerify(size_t maxUniqueSessions,
std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums);
bool CollectPendingSigSharesToVerify(
size_t maxUniqueSessions, std::unordered_map<NodeId, std::vector<CSigShare>>& retSigShares,
std::unordered_map<std::pair<Consensus::LLMQType, uint256>, CQuorumCPtr, StaticSaltedHasher>& retQuorums);
bool ProcessPendingSigShares(const CConnman& connman);

void ProcessPendingSigShares(const std::vector<CSigShare>& sigSharesToProcess,
Expand Down
5 changes: 4 additions & 1 deletion src/masternode/node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ void CActiveMasternodeManager::InitInternal(const CBlockIndex* pindex)

CDeterministicMNList mnList = Assert(m_dmnman)->GetListForBlock(pindex);

CDeterministicMNCPtr dmn = mnList.GetMNByOperatorKey(m_info.blsPubKeyOperator);
auto dmn = mnList.GetMNByOperatorKey(m_info.blsPubKeyOperator);
if (!dmn) {
// MN not appeared on the chain yet
return;
Expand Down Expand Up @@ -166,6 +166,9 @@ void CActiveMasternodeManager::UpdatedBlockTip(const CBlockIndex* pindexNew, con

auto oldDmn = oldMNList.GetMN(cur_protx_hash);
auto newDmn = newMNList.GetMN(cur_protx_hash);
if (oldDmn == nullptr || newDmn == nullptr) {
return reset(MASTERNODE_ERROR);
}
if (newDmn->pdmnState->pubKeyOperator != oldDmn->pdmnState->pubKeyOperator) {
// MN operator key changed or revoked
return reset(MASTERNODE_OPERATOR_KEY_CHANGED);
Expand Down
3 changes: 2 additions & 1 deletion src/qt/masternodelist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,8 @@ CDeterministicMNCPtr MasternodeList::GetSelectedDIP3MN()
uint256 proTxHash;
proTxHash.SetHex(strProTxHash);

return clientModel->getMasternodeList().first.GetMN(proTxHash);;
// Caller is responsible for nullptr checking return value
return clientModel->getMasternodeList().first.GetMN(proTxHash);
}

void MasternodeList::extraInfoDIP3_clicked()
Expand Down
6 changes: 6 additions & 0 deletions src/rpc/evo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1709,13 +1709,19 @@ static RPCHelpMan protx_listdiff()
UniValue jremovedMNs(UniValue::VARR);
for(const auto& internal_id : mnDiff.removedMns) {
auto dmn = baseBlockMNList.GetMNByInternalId(internal_id);
// BuildDiff will construct itself with MNs that we already have knowledge
// of, meaning that fetch operations should never fail.
CHECK_NONFATAL(dmn != nullptr);
jremovedMNs.push_back(dmn->proTxHash.ToString());
}
ret.pushKV("removedMNs", jremovedMNs);

UniValue jupdatedMNs(UniValue::VARR);
for(const auto& [internal_id, stateDiff] : mnDiff.updatedMNs) {
auto dmn = baseBlockMNList.GetMNByInternalId(internal_id);
// BuildDiff will construct itself with MNs that we already have knowledge
// of, meaning that fetch operations should never fail.
CHECK_NONFATAL(dmn != nullptr);
UniValue obj(UniValue::VOBJ);
obj.pushKV(dmn->proTxHash.ToString(), stateDiff.ToJson(dmn->nType));
jupdatedMNs.push_back(obj);
Expand Down
Loading
Loading