refactor: tweak GetLLMQ to fail gracefully and let caller handle results accordingly (#5247)

This allows us to have a bit more granular control over GetLLMQ results,
removes code duplication and also optimises things a tiny bit by
replacing "HasLLMQ + GetLLMQParams" calls with simply "GetLLMQParams".

Use `optional` in `GetLLMQ`, drop `HasLLMQ`.

run tests, reindex on testnet/mainnet

n/a

- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have added or updated relevant unit/integration/functional/e2e
tests
- [ ] I have made corresponding changes to the documentation

**For repository code-owners and collaborators only**
- [x] I have assigned this pull request to a milestone
This commit is contained in:
UdjinM6 2023-03-14 20:38:35 +03:00
parent 0fa86b3446
commit f08488d0cb
No known key found for this signature in database
GPG Key ID: 83592BD1400D58D9
25 changed files with 222 additions and 145 deletions

View File

@ -110,7 +110,7 @@ static CBlock FindDevNetGenesisBlock(const CBlock &prevBlock, const CAmount& rew
void CChainParams::AddLLMQ(Consensus::LLMQType llmqType) void CChainParams::AddLLMQ(Consensus::LLMQType llmqType)
{ {
assert(!HasLLMQ(llmqType)); assert(!GetLLMQ(llmqType).has_value());
for (const auto& llmq_param : Consensus::available_llmqs) { for (const auto& llmq_param : Consensus::available_llmqs) {
if (llmq_param.type == llmqType) { if (llmq_param.type == llmqType) {
consensus.llmqs.push_back(llmq_param); consensus.llmqs.push_back(llmq_param);
@ -121,25 +121,14 @@ void CChainParams::AddLLMQ(Consensus::LLMQType llmqType)
assert(false); assert(false);
} }
const Consensus::LLMQParams& CChainParams::GetLLMQ(Consensus::LLMQType llmqType) const std::optional<Consensus::LLMQParams> CChainParams::GetLLMQ(Consensus::LLMQType llmqType) const
{ {
for (const auto& llmq_param : consensus.llmqs) { for (const auto& llmq_param : consensus.llmqs) {
if (llmq_param.type == llmqType) { if (llmq_param.type == llmqType) {
return llmq_param; return std::make_optional(llmq_param);
} }
} }
error("CChainParams::%s: unknown LLMQ type %d", __func__, static_cast<uint8_t>(llmqType)); return std::nullopt;
assert(false);
}
bool CChainParams::HasLLMQ(Consensus::LLMQType llmqType) const
{
for (const auto& llmq_param : consensus.llmqs) {
if (llmq_param.type == llmqType) {
return true;
}
}
return false;
} }
/** /**
@ -1231,7 +1220,10 @@ void CDevNetParams::UpdateDevnetLLMQChainLocksFromArgs(const ArgsManager& args)
{ {
if (!args.IsArgSet("-llmqchainlocks")) return; if (!args.IsArgSet("-llmqchainlocks")) return;
std::string strLLMQType = gArgs.GetArg("-llmqchainlocks", std::string(GetLLMQ(consensus.llmqTypeChainLocks).name)); const auto& llmq_params_opt = GetLLMQ(consensus.llmqTypeChainLocks);
assert(llmq_params_opt.has_value());
std::string strLLMQType = gArgs.GetArg("-llmqchainlocks", std::string(llmq_params_opt->name));
Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE; Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE;
for (const auto& params : consensus.llmqs) { for (const auto& params : consensus.llmqs) {
@ -1253,7 +1245,10 @@ void CDevNetParams::UpdateDevnetLLMQInstantSendFromArgs(const ArgsManager& args)
{ {
if (!args.IsArgSet("-llmqinstantsend")) return; if (!args.IsArgSet("-llmqinstantsend")) return;
std::string strLLMQType = gArgs.GetArg("-llmqinstantsend", std::string(GetLLMQ(consensus.llmqTypeInstantSend).name)); const auto& llmq_params_opt = GetLLMQ(consensus.llmqTypeInstantSend);
assert(llmq_params_opt.has_value());
std::string strLLMQType = gArgs.GetArg("-llmqinstantsend", std::string(llmq_params_opt->name));
Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE; Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE;
for (const auto& params : consensus.llmqs) { for (const auto& params : consensus.llmqs) {
@ -1275,7 +1270,10 @@ void CDevNetParams::UpdateDevnetLLMQInstantSendDIP0024FromArgs(const ArgsManager
{ {
if (!args.IsArgSet("-llmqinstantsenddip0024")) return; if (!args.IsArgSet("-llmqinstantsenddip0024")) return;
std::string strLLMQType = gArgs.GetArg("-llmqinstantsenddip0024", std::string(GetLLMQ(consensus.llmqTypeDIP0024InstantSend).name)); const auto& llmq_params_opt = GetLLMQ(consensus.llmqTypeDIP0024InstantSend);
assert(llmq_params_opt.has_value());
std::string strLLMQType = gArgs.GetArg("-llmqinstantsenddip0024", std::string(llmq_params_opt->name));
Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE; Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE;
for (const auto& params : consensus.llmqs) { for (const auto& params : consensus.llmqs) {

View File

@ -110,8 +110,7 @@ public:
const std::vector<std::string>& SporkAddresses() const { return vSporkAddresses; } const std::vector<std::string>& SporkAddresses() const { return vSporkAddresses; }
int MinSporkKeys() const { return nMinSporkKeys; } int MinSporkKeys() const { return nMinSporkKeys; }
bool BIP9CheckMasternodesUpgraded() const { return fBIP9CheckMasternodesUpgraded; } bool BIP9CheckMasternodesUpgraded() const { return fBIP9CheckMasternodesUpgraded; }
const Consensus::LLMQParams& GetLLMQ(Consensus::LLMQType llmqType) const; std::optional<Consensus::LLMQParams> GetLLMQ(Consensus::LLMQType llmqType) const;
bool HasLLMQ(Consensus::LLMQType llmqType) const;
protected: protected:
CChainParams() {} CChainParams() {}

View File

@ -188,7 +188,9 @@ auto CachedGetQcHashesQcIndexedHashes(const CBlockIndex* pindexPrev, const llmq:
qcIndexedHashes_cached.clear(); qcIndexedHashes_cached.clear();
for (const auto& [llmqType, vecBlockIndexes] : quorums) { for (const auto& [llmqType, vecBlockIndexes] : quorums) {
bool rotation_enabled = llmq::utils::IsQuorumRotationEnabled(llmqType, pindexPrev); const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
bool rotation_enabled = llmq::utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindexPrev);
auto& vec_hashes = qcHashes_cached[llmqType]; auto& vec_hashes = qcHashes_cached[llmqType];
vec_hashes.reserve(vecBlockIndexes.size()); vec_hashes.reserve(vecBlockIndexes.size());
auto& map_indexed_hashes = qcIndexedHashes_cached[llmqType]; auto& map_indexed_hashes = qcIndexedHashes_cached[llmqType];
@ -252,12 +254,16 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
// having null commitments is ok but we don't use them here, move to the next tx // having null commitments is ok but we don't use them here, move to the next tx
continue; continue;
} }
const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
if (!llmq_params_opt.has_value()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot");
}
const auto& llmq_params = llmq_params_opt.value();
auto qcHash = ::SerializeHash(qc.commitment); auto qcHash = ::SerializeHash(qc.commitment);
if (llmq::utils::IsQuorumRotationEnabled(qc.commitment.llmqType, pindexPrev)) { if (llmq::utils::IsQuorumRotationEnabled(llmq_params, pindexPrev)) {
auto& map_indexed_hashes = qcIndexedHashes[qc.commitment.llmqType]; auto& map_indexed_hashes = qcIndexedHashes[qc.commitment.llmqType];
map_indexed_hashes[qc.commitment.quorumIndex] = qcHash; map_indexed_hashes[qc.commitment.quorumIndex] = qcHash;
} else { } else {
const auto& llmq_params = llmq::GetLLMQParams(qc.commitment.llmqType);
auto& vec_hashes = qcHashes[llmq_params.type]; auto& vec_hashes = qcHashes[llmq_params.type];
if (vec_hashes.size() == size_t(llmq_params.signingActiveQuorumCount)) { if (vec_hashes.size() == size_t(llmq_params.signingActiveQuorumCount)) {
// we pop the last entry, which is actually the oldest quorum as GetMinedAndActiveCommitmentsUntilBlock // we pop the last entry, which is actually the oldest quorum as GetMinedAndActiveCommitmentsUntilBlock
@ -281,8 +287,9 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre
vec_hashes_final.reserve(CalcHashCountFromQCHashes(qcHashes)); vec_hashes_final.reserve(CalcHashCountFromQCHashes(qcHashes));
for (const auto& [llmqType, vec_hashes] : qcHashes) { for (const auto& [llmqType, vec_hashes] : qcHashes) {
const auto& llmq_params = llmq::GetLLMQParams(llmqType); const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
if (vec_hashes.size() > size_t(llmq_params.signingActiveQuorumCount)) { assert(llmq_params_opt.has_value());
if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "excess-quorums-calc-cbtx-quorummerkleroot"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "excess-quorums-calc-cbtx-quorummerkleroot");
} }
// Copy vec_hashes into vec_hashes_final // Copy vec_hashes into vec_hashes_final

View File

@ -829,9 +829,12 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, const C
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload"); return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
} }
if (!qc.commitment.IsNull()) { if (!qc.commitment.IsNull()) {
const auto& llmq_params = llmq::GetLLMQParams(qc.commitment.llmqType); const auto& llmq_params_opt = llmq::GetLLMQParams(qc.commitment.llmqType);
if (!llmq_params_opt.has_value()) {
return _state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
}
int qcnHeight = int(qc.nHeight); int qcnHeight = int(qc.nHeight);
int quorumHeight = qcnHeight - (qcnHeight % llmq_params.dkgInterval) + int(qc.commitment.quorumIndex); int quorumHeight = qcnHeight - (qcnHeight % llmq_params_opt->dkgInterval) + int(qc.commitment.quorumIndex);
auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight); auto pQuorumBaseBlockIndex = pindexPrev->GetAncestor(quorumHeight);
if (!pQuorumBaseBlockIndex || pQuorumBaseBlockIndex->GetBlockHash() != qc.commitment.quorumHash) { if (!pQuorumBaseBlockIndex || pQuorumBaseBlockIndex->GetBlockHash() != qc.commitment.quorumHash) {
// we should actually never get into this case as validation should have caught it...but let's be sure // we should actually never get into this case as validation should have caught it...but let's be sure

View File

@ -25,7 +25,9 @@ bool MNHFTx::Verify(const CBlockIndex* pQuorumIndex) const
} }
Consensus::LLMQType llmqType = Params().GetConsensus().llmqTypeMnhf; Consensus::LLMQType llmqType = Params().GetConsensus().llmqTypeMnhf;
int signOffset{llmq::GetLLMQParams(llmqType).dkgInterval}; const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
int signOffset{llmq_params_opt->dkgInterval};
const uint256 requestId = ::SerializeHash(std::make_pair(CBLSIG_REQUESTID_PREFIX, pQuorumIndex->nHeight)); const uint256 requestId = ::SerializeHash(std::make_pair(CBLSIG_REQUESTID_PREFIX, pQuorumIndex->nHeight));
return llmq::CSigningManager::VerifyRecoveredSig(llmqType, *llmq::quorumManager, pQuorumIndex->nHeight, requestId, pQuorumIndex->GetBlockHash(), sig, 0) || return llmq::CSigningManager::VerifyRecoveredSig(llmqType, *llmq::quorumManager, pQuorumIndex->nHeight, requestId, pQuorumIndex->GetBlockHash(), sig, 0) ||
@ -53,7 +55,7 @@ bool CheckMNHFTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidat
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-quorum-hash");
} }
if (!Params().HasLLMQ(Params().GetConsensus().llmqTypeMnhf)) { if (!llmq::GetLLMQParams(Params().GetConsensus().llmqTypeMnhf).has_value()) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-type"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-mnhf-type");
} }

View File

@ -58,7 +58,8 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
return; return;
} }
if (!Params().HasLLMQ(qc.llmqType)) { const auto& llmq_params_opt = GetLLMQParams(qc.llmqType);
if (!llmq_params_opt.has_value()) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- invalid commitment type %d from peer=%d\n", __func__, LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- invalid commitment type %d from peer=%d\n", __func__,
uint8_t(qc.llmqType), peer.GetId()); uint8_t(qc.llmqType), peer.GetId());
WITH_LOCK(cs_main, Misbehaving(peer.GetId(), 100)); WITH_LOCK(cs_main, Misbehaving(peer.GetId(), 100));
@ -84,14 +85,14 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
// same, can't punish // same, can't punish
return; return;
} }
int quorumHeight = pQuorumBaseBlockIndex->nHeight - (pQuorumBaseBlockIndex->nHeight % GetLLMQParams(type).dkgInterval) + int(qc.quorumIndex); int quorumHeight = pQuorumBaseBlockIndex->nHeight - (pQuorumBaseBlockIndex->nHeight % llmq_params_opt->dkgInterval) + int(qc.quorumIndex);
if (quorumHeight != pQuorumBaseBlockIndex->nHeight) { if (quorumHeight != pQuorumBaseBlockIndex->nHeight) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- block %s is not the first block in the DKG interval, peer=%d\n", __func__, LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- block %s is not the first block in the DKG interval, peer=%d\n", __func__,
qc.quorumHash.ToString(), peer.GetId()); qc.quorumHash.ToString(), peer.GetId());
Misbehaving(peer.GetId(), 100); Misbehaving(peer.GetId(), 100);
return; return;
} }
if (pQuorumBaseBlockIndex->nHeight < (::ChainActive().Height() - GetLLMQParams(type).dkgInterval)) { if (pQuorumBaseBlockIndex->nHeight < (::ChainActive().Height() - llmq_params_opt->dkgInterval)) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- block %s is too old, peer=%d\n", __func__, LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- block %s is too old, peer=%d\n", __func__,
qc.quorumHash.ToString(), peer.GetId()); qc.quorumHash.ToString(), peer.GetId());
// TODO: enable punishment in some future version when all/most nodes are running with this fix // TODO: enable punishment in some future version when all/most nodes are running with this fix
@ -173,7 +174,7 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, const CBlockIndex*
if (numCommitmentsRequired > numCommitmentsInNewBlock) { if (numCommitmentsRequired > numCommitmentsInNewBlock) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-missing"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-missing");
} }
if (llmq::utils::IsQuorumRotationEnabled(params.type, pindex)) { if (llmq::utils::IsQuorumRotationEnabled(params, pindex)) {
LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock); LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock);
} }
} }
@ -209,7 +210,12 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
{ {
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
const auto& llmq_params = GetLLMQParams(qc.llmqType); const auto& llmq_params_opt = GetLLMQParams(qc.llmqType);
if (!llmq_params_opt.has_value()) {
LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- invalid commitment type %d\n", __func__, static_cast<uint8_t>(qc.llmqType));
return false;
}
const auto& llmq_params = llmq_params_opt.value();
uint256 quorumHash = GetQuorumBlockHash(llmq_params, nHeight, qc.quorumIndex); uint256 quorumHash = GetQuorumBlockHash(llmq_params, nHeight, qc.quorumIndex);
@ -263,7 +269,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
return true; return true;
} }
bool rotation_enabled = utils::IsQuorumRotationEnabled(llmq_params.type, pQuorumBaseBlockIndex); bool rotation_enabled = utils::IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex);
if (rotation_enabled) { if (rotation_enabled) {
LogPrint(BCLog::LLMQ, "[ProcessCommitment] height[%d] pQuorumBaseBlockIndex[%d] quorumIndex[%d] qversion[%d] Built\n", LogPrint(BCLog::LLMQ, "[ProcessCommitment] height[%d] pQuorumBaseBlockIndex[%d] quorumIndex[%d] qversion[%d] Built\n",
@ -313,7 +319,10 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, const CBlockIndex* pi
evoDb.Erase(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(qc.llmqType, qc.quorumHash))); evoDb.Erase(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(qc.llmqType, qc.quorumHash)));
if (llmq::utils::IsQuorumRotationEnabled(qc.llmqType, pindex)) { const auto& llmq_params_opt = GetLLMQParams(qc.llmqType);
assert(llmq_params_opt.has_value());
if (llmq::utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
evoDb.Erase(BuildInversedHeightKeyIndexed(qc.llmqType, pindex->nHeight, int(qc.quorumIndex))); evoDb.Erase(BuildInversedHeightKeyIndexed(qc.llmqType, pindex->nHeight, int(qc.quorumIndex)));
} else { } else {
evoDb.Erase(BuildInversedHeightKey(qc.llmqType, pindex->nHeight)); evoDb.Erase(BuildInversedHeightKey(qc.llmqType, pindex->nHeight));
@ -372,7 +381,9 @@ bool CQuorumBlockProcessor::UpgradeDB()
} }
const auto* pQuorumBaseBlockIndex = LookupBlockIndex(qc.quorumHash); const auto* pQuorumBaseBlockIndex = LookupBlockIndex(qc.quorumHash);
evoDb.GetRawDB().Write(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(qc.llmqType, qc.quorumHash)), std::make_pair(qc, pindex->GetBlockHash())); evoDb.GetRawDB().Write(std::make_pair(DB_MINED_COMMITMENT, std::make_pair(qc.llmqType, qc.quorumHash)), std::make_pair(qc, pindex->GetBlockHash()));
if (llmq::utils::IsQuorumRotationEnabled(qc.llmqType, pQuorumBaseBlockIndex)) { const auto& llmq_params_opt = GetLLMQParams(qc.llmqType);
assert(llmq_params_opt.has_value());
if (llmq::utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pQuorumBaseBlockIndex)) {
evoDb.GetRawDB().Write(BuildInversedHeightKeyIndexed(qc.llmqType, pindex->nHeight, int(qc.quorumIndex)), pQuorumBaseBlockIndex->nHeight); evoDb.GetRawDB().Write(BuildInversedHeightKeyIndexed(qc.llmqType, pindex->nHeight, int(qc.quorumIndex)), pQuorumBaseBlockIndex->nHeight);
} else { } else {
evoDb.GetRawDB().Write(BuildInversedHeightKey(qc.llmqType, pindex->nHeight), pQuorumBaseBlockIndex->nHeight); evoDb.GetRawDB().Write(BuildInversedHeightKey(qc.llmqType, pindex->nHeight), pQuorumBaseBlockIndex->nHeight);
@ -406,8 +417,14 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, const C
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
} }
const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType);
if (!llmq_params_opt.has_value()) {
// should not happen as it was verified before processing the block
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
}
// only allow one commitment per type and per block (This was changed with rotation) // only allow one commitment per type and per block (This was changed with rotation)
if (!utils::IsQuorumRotationEnabled(qc.commitment.llmqType, pindex)) { if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
if (ret.count(qc.commitment.llmqType) != 0) { if (ret.count(qc.commitment.llmqType) != 0) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-dup");
} }
@ -454,7 +471,7 @@ size_t CQuorumBlockProcessor::GetNumCommitmentsRequired(const Consensus::LLMQPar
assert(nHeight <= ::ChainActive().Height() + 1); assert(nHeight <= ::ChainActive().Height() + 1);
const auto *const pindex = ::ChainActive().Height() < nHeight ? ::ChainActive().Tip() : ::ChainActive().Tip()->GetAncestor(nHeight); const auto *const pindex = ::ChainActive().Height() < nHeight ? ::ChainActive().Tip() : ::ChainActive().Tip()->GetAncestor(nHeight);
bool rotation_enabled = utils::IsQuorumRotationEnabled(llmqParams.type, pindex); bool rotation_enabled = utils::IsQuorumRotationEnabled(llmqParams, pindex);
size_t quorums_num = rotation_enabled ? llmqParams.signingActiveQuorumCount : 1; size_t quorums_num = rotation_enabled ? llmqParams.signingActiveQuorumCount : 1;
size_t ret{0}; size_t ret{0};
@ -607,10 +624,11 @@ std::optional<const CBlockIndex*> CQuorumBlockProcessor::GetLastMinedCommitments
std::vector<std::pair<int, const CBlockIndex*>> CQuorumBlockProcessor::GetLastMinedCommitmentsPerQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t cycle) const std::vector<std::pair<int, const CBlockIndex*>> CQuorumBlockProcessor::GetLastMinedCommitmentsPerQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t cycle) const
{ {
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType); const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
std::vector<std::pair<int, const CBlockIndex*>> ret; std::vector<std::pair<int, const CBlockIndex*>> ret;
for (const auto quorumIndex : irange::range(llmqParams.signingActiveQuorumCount)) { for (const auto quorumIndex : irange::range(llmq_params_opt->signingActiveQuorumCount)) {
std::optional<const CBlockIndex*> q = GetLastMinedCommitmentsByQuorumIndexUntilBlock(llmqType, pindex, quorumIndex, cycle); std::optional<const CBlockIndex*> q = GetLastMinedCommitmentsByQuorumIndexUntilBlock(llmqType, pindex, quorumIndex, cycle);
if (q.has_value()) { if (q.has_value()) {
ret.emplace_back(quorumIndex, q.value()); ret.emplace_back(quorumIndex, q.value());
@ -658,7 +676,7 @@ std::map<Consensus::LLMQType, std::vector<const CBlockIndex*>> CQuorumBlockProce
for (const auto& params : Params().GetConsensus().llmqs) { for (const auto& params : Params().GetConsensus().llmqs) {
auto& v = ret[params.type]; auto& v = ret[params.type];
v.reserve(params.signingActiveQuorumCount); v.reserve(params.signingActiveQuorumCount);
if (utils::IsQuorumRotationEnabled(params.type, pindex)) { if (utils::IsQuorumRotationEnabled(params, pindex)) {
std::vector<std::pair<int, const CBlockIndex*>> commitments = GetLastMinedCommitmentsPerQuorumIndexUntilBlock(params.type, pindex, 0); std::vector<std::pair<int, const CBlockIndex*>> commitments = GetLastMinedCommitmentsPerQuorumIndexUntilBlock(params.type, pindex, 0);
std::transform(commitments.begin(), commitments.end(), std::back_inserter(v), std::transform(commitments.begin(), commitments.end(), std::back_inserter(v),
[](const std::pair<int, const CBlockIndex*>& p) { return p.second; }); [](const std::pair<int, const CBlockIndex*>& p) { return p.second; });
@ -737,7 +755,7 @@ std::optional<std::vector<CFinalCommitment>> CQuorumBlockProcessor::GetMineableC
assert(nHeight <= ::ChainActive().Height() + 1); assert(nHeight <= ::ChainActive().Height() + 1);
const auto *const pindex = ::ChainActive().Height() < nHeight ? ::ChainActive().Tip() : ::ChainActive().Tip()->GetAncestor(nHeight); const auto *const pindex = ::ChainActive().Height() < nHeight ? ::ChainActive().Tip() : ::ChainActive().Tip()->GetAncestor(nHeight);
bool rotation_enabled = utils::IsQuorumRotationEnabled(llmqParams.type, pindex); bool rotation_enabled = utils::IsQuorumRotationEnabled(llmqParams, pindex);
size_t quorums_num = rotation_enabled ? llmqParams.signingActiveQuorumCount : 1; size_t quorums_num = rotation_enabled ? llmqParams.signingActiveQuorumCount : 1;
std::stringstream ss; std::stringstream ss;

View File

@ -30,16 +30,17 @@ CFinalCommitment::CFinalCommitment(const Consensus::LLMQParams& params, const ui
bool CFinalCommitment::Verify(const CBlockIndex* pQuorumBaseBlockIndex, bool checkSigs) const bool CFinalCommitment::Verify(const CBlockIndex* pQuorumBaseBlockIndex, bool checkSigs) const
{ {
if (nVersion == 0 || nVersion != (utils::IsQuorumRotationEnabled(llmqType, pQuorumBaseBlockIndex) ? INDEXED_QUORUM_VERSION : CURRENT_VERSION)) { const auto& llmq_params_opt = GetLLMQParams(llmqType);
LogPrintfFinalCommitment("q[%s] invalid nVersion=%d\n", quorumHash.ToString(), nVersion); if (!llmq_params_opt.has_value()) {
return false;
}
if (!Params().HasLLMQ(llmqType)) {
LogPrintfFinalCommitment("q[%s] invalid llmqType=%d\n", quorumHash.ToString(), static_cast<uint8_t>(llmqType)); LogPrintfFinalCommitment("q[%s] invalid llmqType=%d\n", quorumHash.ToString(), static_cast<uint8_t>(llmqType));
return false; return false;
} }
const auto& llmq_params = GetLLMQParams(llmqType); const auto& llmq_params = llmq_params_opt.value();
if (nVersion == 0 || nVersion != (utils::IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex) ? INDEXED_QUORUM_VERSION : CURRENT_VERSION)) {
LogPrintfFinalCommitment("q[%s] invalid nVersion=%d\n", quorumHash.ToString(), nVersion);
return false;
}
if (pQuorumBaseBlockIndex->GetBlockHash() != quorumHash) { if (pQuorumBaseBlockIndex->GetBlockHash() != quorumHash) {
LogPrintfFinalCommitment("q[%s] invalid quorumHash\n", quorumHash.ToString()); LogPrintfFinalCommitment("q[%s] invalid quorumHash\n", quorumHash.ToString());
@ -138,12 +139,13 @@ bool CFinalCommitment::Verify(const CBlockIndex* pQuorumBaseBlockIndex, bool che
bool CFinalCommitment::VerifyNull() const bool CFinalCommitment::VerifyNull() const
{ {
if (!Params().HasLLMQ(llmqType)) { const auto& llmq_params_opt = GetLLMQParams(llmqType);
if (!llmq_params_opt.has_value()) {
LogPrintfFinalCommitment("q[%s]invalid llmqType=%d\n", quorumHash.ToString(), static_cast<uint8_t>(llmqType)); LogPrintfFinalCommitment("q[%s]invalid llmqType=%d\n", quorumHash.ToString(), static_cast<uint8_t>(llmqType));
return false; return false;
} }
if (!IsNull() || !VerifySizes(GetLLMQParams(llmqType))) { if (!IsNull() || !VerifySizes(llmq_params_opt.value())) {
return false; return false;
} }
@ -170,10 +172,16 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev,
LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight); LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight);
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-payload");
} }
const auto& llmq_params = GetLLMQParams(qcTx.commitment.llmqType);
const auto& llmq_params_opt = GetLLMQParams(qcTx.commitment.llmqType);
if (!llmq_params_opt.has_value()) {
LogPrintfFinalCommitment("h[%d] GetLLMQParams failed for llmqType[%d]\n", pindexPrev->nHeight, static_cast<uint8_t>(qcTx.commitment.llmqType));
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-commitment-type");
}
if (LogAcceptCategory(BCLog::LLMQ)) { if (LogAcceptCategory(BCLog::LLMQ)) {
std::stringstream ss; std::stringstream ss;
for (const auto i: irange::range(llmq_params.size)) { for (const auto i: irange::range(llmq_params_opt->size)) {
ss << "v[" << i << "]=" << qcTx.commitment.validMembers[i]; ss << "v[" << i << "]=" << qcTx.commitment.validMembers[i];
} }
LogPrintfFinalCommitment("%s llmqType[%d] validMembers[%s] signers[]\n", __func__, LogPrintfFinalCommitment("%s llmqType[%d] validMembers[%s] signers[]\n", __func__,
@ -201,10 +209,6 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev,
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash"); return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-quorum-hash");
} }
if (!Params().HasLLMQ(qcTx.commitment.llmqType)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-type");
}
if (qcTx.commitment.IsNull()) { if (qcTx.commitment.IsNull()) {
if (!qcTx.commitment.VerifyNull()) { if (!qcTx.commitment.VerifyNull()) {
LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString()); LogPrintfFinalCommitment("h[%d] invalid qcTx.commitment[%s] VerifyNull failed\n", pindexPrev->nHeight, qcTx.commitment.quorumHash.ToString());

View File

@ -18,7 +18,7 @@ UniValue CDKGDebugSessionStatus::ToJson(int quorumIndex, int detailLevel) const
{ {
UniValue ret(UniValue::VOBJ); UniValue ret(UniValue::VOBJ);
if (!Params().HasLLMQ(llmqType) || quorumHash.IsNull()) { if (!GetLLMQParams(llmqType).has_value() || quorumHash.IsNull()) {
return ret; return ret;
} }
@ -117,11 +117,12 @@ UniValue CDKGDebugStatus::ToJson(int detailLevel) const
// TODO Support array of sessions // TODO Support array of sessions
UniValue sessionsArrJson(UniValue::VARR); UniValue sessionsArrJson(UniValue::VARR);
for (const auto& p : sessions) { for (const auto& p : sessions) {
if (!Params().HasLLMQ(p.first.first)) { const auto& llmq_params_opt = GetLLMQParams(p.first.first);
if (!llmq_params_opt.has_value()) {
continue; continue;
} }
UniValue s(UniValue::VOBJ); UniValue s(UniValue::VOBJ);
s.pushKV("llmqType", std::string(GetLLMQParams(p.first.first).name)); s.pushKV("llmqType", std::string(llmq_params_opt->name));
s.pushKV("quorumIndex", p.first.second); s.pushKV("quorumIndex", p.first.second);
s.pushKV("status", p.second.ToJson(p.first.second, detailLevel)); s.pushKV("status", p.second.ToJson(p.first.second, detailLevel));

View File

@ -85,7 +85,7 @@ bool CDKGSession::Init(const CBlockIndex* _pQuorumBaseBlockIndex, const std::vec
CDKGLogger logger(*this, __func__); CDKGLogger logger(*this, __func__);
if (LogAcceptCategory(BCLog::LLMQ) && utils::IsQuorumRotationEnabled(params.type, m_quorum_base_block_index)) { if (LogAcceptCategory(BCLog::LLMQ) && utils::IsQuorumRotationEnabled(params, m_quorum_base_block_index)) {
int cycleQuorumBaseHeight = m_quorum_base_block_index->nHeight - quorumIndex; int cycleQuorumBaseHeight = m_quorum_base_block_index->nHeight - quorumIndex;
const CBlockIndex* pCycleQuorumBaseBlockIndex = m_quorum_base_block_index->GetAncestor(cycleQuorumBaseHeight); const CBlockIndex* pCycleQuorumBaseBlockIndex = m_quorum_base_block_index->GetAncestor(cycleQuorumBaseHeight);
std::stringstream ss; std::stringstream ss;
@ -1206,7 +1206,7 @@ std::vector<CFinalCommitment> CDKGSession::FinalizeCommitments()
fqc.quorumPublicKey = first.quorumPublicKey; fqc.quorumPublicKey = first.quorumPublicKey;
fqc.quorumVvecHash = first.quorumVvecHash; fqc.quorumVvecHash = first.quorumVvecHash;
if (utils::IsQuorumRotationEnabled(fqc.llmqType, m_quorum_base_block_index)) { if (utils::IsQuorumRotationEnabled(params, m_quorum_base_block_index)) {
fqc.nVersion = CFinalCommitment::INDEXED_QUORUM_VERSION; fqc.nVersion = CFinalCommitment::INDEXED_QUORUM_VERSION;
fqc.quorumIndex = quorumIndex; fqc.quorumIndex = quorumIndex;
} else { } else {

View File

@ -256,7 +256,7 @@ class CDKGSession
friend class CDKGLogger; friend class CDKGLogger;
private: private:
const Consensus::LLMQParams& params; const Consensus::LLMQParams params;
CBLSWorker& blsWorker; CBLSWorker& blsWorker;
CBLSWorkerCache cache; CBLSWorkerCache cache;

View File

@ -84,7 +84,7 @@ void CDKGSessionHandler::UpdatedBlockTip(const CBlockIndex* pindexNew)
{ {
//AssertLockNotHeld(cs_main); //AssertLockNotHeld(cs_main);
//Indexed quorums (greater than 0) are enabled with Quorum Rotation //Indexed quorums (greater than 0) are enabled with Quorum Rotation
if (quorumIndex > 0 && !utils::IsQuorumRotationEnabled(params.type, pindexNew)) { if (quorumIndex > 0 && !utils::IsQuorumRotationEnabled(params, pindexNew)) {
return; return;
} }
LOCK(cs); LOCK(cs);

View File

@ -109,7 +109,7 @@ private:
mutable CCriticalSection cs; mutable CCriticalSection cs;
std::atomic<bool> stopRequested{false}; std::atomic<bool> stopRequested{false};
const Consensus::LLMQParams& params; const Consensus::LLMQParams params;
CConnman& connman; CConnman& connman;
const int quorumIndex; const int quorumIndex;
CBLSWorker& blsWorker; CBLSWorker& blsWorker;

View File

@ -196,12 +196,14 @@ void CDKGSessionManager::ProcessMessage(CNode* pfrom, const CQuorumManager& quor
vRecv.Rewind(sizeof(uint256)); vRecv.Rewind(sizeof(uint256));
vRecv.Rewind(sizeof(uint8_t)); vRecv.Rewind(sizeof(uint8_t));
if (!Params().HasLLMQ(llmqType)) { const auto& llmq_params_opt = GetLLMQParams(llmqType);
if (!llmq_params_opt.has_value()) {
LOCK(cs_main); LOCK(cs_main);
LogPrintf("CDKGSessionManager -- invalid llmqType [%d]\n", uint8_t(llmqType)); LogPrintf("CDKGSessionManager -- invalid llmqType [%d]\n", uint8_t(llmqType));
Misbehaving(pfrom->GetId(), 100); Misbehaving(pfrom->GetId(), 100);
return; return;
} }
const auto& llmq_params = llmq_params_opt.value();
int quorumIndex{-1}; int quorumIndex{-1};
@ -232,10 +234,9 @@ void CDKGSessionManager::ProcessMessage(CNode* pfrom, const CQuorumManager& quor
return; return;
} }
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType); quorumIndex = pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval;
quorumIndex = pQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval; int quorumIndexMax = utils::IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex) ?
int quorumIndexMax = utils::IsQuorumRotationEnabled(llmqType, pQuorumBaseBlockIndex) ? llmq_params.signingActiveQuorumCount - 1 : 0;
llmqParams.signingActiveQuorumCount - 1 : 0;
if (quorumIndex > quorumIndexMax) { if (quorumIndex > quorumIndexMax) {
LOCK(cs_main); LOCK(cs_main);

View File

@ -706,8 +706,10 @@ void CInstantSendManager::TrySignInstantSendLock(const CTransaction& tx)
// compute and set cycle hash if islock is deterministic // compute and set cycle hash if islock is deterministic
if (islock.IsDeterministic()) { if (islock.IsDeterministic()) {
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt);
LOCK(cs_main); LOCK(cs_main);
const auto dkgInterval = GetLLMQParams(llmqType).dkgInterval; const auto dkgInterval = llmq_params_opt->dkgInterval;
const auto quorumHeight = ::ChainActive().Height() - (::ChainActive().Height() % dkgInterval); const auto quorumHeight = ::ChainActive().Height() - (::ChainActive().Height() % dkgInterval);
islock.cycleHash = ::ChainActive()[quorumHeight]->GetBlockHash(); islock.cycleHash = ::ChainActive()[quorumHeight]->GetBlockHash();
} }
@ -804,7 +806,9 @@ void CInstantSendManager::ProcessMessageInstantSendLock(const CNode* pfrom, cons
// Deterministic islocks MUST use rotation based llmq // Deterministic islocks MUST use rotation based llmq
auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend;
if (blockIndex->nHeight % GetLLMQParams(llmqType).dkgInterval != 0) { const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt);
if (blockIndex->nHeight % llmq_params_opt->dkgInterval != 0) {
WITH_LOCK(cs_main, Misbehaving(pfrom->GetId(), 100)); WITH_LOCK(cs_main, Misbehaving(pfrom->GetId(), 100));
return; return;
} }
@ -905,10 +909,13 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks(bool deterministic)
//TODO Investigate if leaving this is ok //TODO Investigate if leaving this is ok
auto llmqType = utils::GetInstantSendLLMQType(deterministic); auto llmqType = utils::GetInstantSendLLMQType(deterministic);
auto dkgInterval = GetLLMQParams(llmqType).dkgInterval; const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt);
const auto& llmq_params = llmq_params_opt.value();
auto dkgInterval = llmq_params.dkgInterval;
// First check against the current active set and don't ban // First check against the current active set and don't ban
auto badISLocks = ProcessPendingInstantSendLocks(llmqType, 0, pend, false); auto badISLocks = ProcessPendingInstantSendLocks(llmq_params, 0, pend, false);
if (!badISLocks.empty()) { if (!badISLocks.empty()) {
LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- doing verification on old active set\n", __func__); LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- doing verification on old active set\n", __func__);
@ -921,13 +928,13 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks(bool deterministic)
} }
} }
// Now check against the previous active set and perform banning if this fails // Now check against the previous active set and perform banning if this fails
ProcessPendingInstantSendLocks(llmqType, dkgInterval, pend, true); ProcessPendingInstantSendLocks(llmq_params, dkgInterval, pend, true);
} }
return fMoreWork; return fMoreWork;
} }
std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPendingInstantSendLocks(const Consensus::LLMQType llmqType, int signOffset, const std::unordered_map<uint256, std::pair<NodeId, CInstantSendLockPtr>, StaticSaltedHasher>& pend, bool ban) std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPendingInstantSendLocks(const Consensus::LLMQParams& llmq_params, int signOffset, const std::unordered_map<uint256, std::pair<NodeId, CInstantSendLockPtr>, StaticSaltedHasher>& pend, bool ban)
{ {
CBLSBatchVerifier<NodeId, uint256> batchVerifier(false, true, 8); CBLSBatchVerifier<NodeId, uint256> batchVerifier(false, true, 8);
std::unordered_map<uint256, CRecoveredSig, StaticSaltedHasher> recSigs; std::unordered_map<uint256, CRecoveredSig, StaticSaltedHasher> recSigs;
@ -951,7 +958,7 @@ std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPend
auto id = islock->GetRequestId(); auto id = islock->GetRequestId();
// no need to verify an ISLOCK if we already have verified the recovered sig that belongs to it // no need to verify an ISLOCK if we already have verified the recovered sig that belongs to it
if (sigman.HasRecoveredSig(llmqType, id, islock->txid)) { if (sigman.HasRecoveredSig(llmq_params.type, id, islock->txid)) {
alreadyVerified++; alreadyVerified++;
continue; continue;
} }
@ -966,26 +973,26 @@ std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPend
continue; continue;
} }
const auto dkgInterval = GetLLMQParams(llmqType).dkgInterval; const auto dkgInterval = llmq_params.dkgInterval;
if (blockIndex->nHeight + dkgInterval < ::ChainActive().Height()) { if (blockIndex->nHeight + dkgInterval < ::ChainActive().Height()) {
nSignHeight = blockIndex->nHeight + dkgInterval - 1; nSignHeight = blockIndex->nHeight + dkgInterval - 1;
} }
} }
auto quorum = llmq::CSigningManager::SelectQuorumForSigning(llmqType, qman, id, nSignHeight, signOffset); auto quorum = llmq::CSigningManager::SelectQuorumForSigning(llmq_params, qman, id, nSignHeight, signOffset);
if (!quorum) { if (!quorum) {
// should not happen, but if one fails to select, all others will also fail to select // should not happen, but if one fails to select, all others will also fail to select
return {}; return {};
} }
uint256 signHash = utils::BuildSignHash(llmqType, quorum->qc->quorumHash, id, islock->txid); uint256 signHash = utils::BuildSignHash(llmq_params.type, quorum->qc->quorumHash, id, islock->txid);
batchVerifier.PushMessage(nodeId, hash, signHash, islock->sig.Get(), quorum->qc->quorumPublicKey); batchVerifier.PushMessage(nodeId, hash, signHash, islock->sig.Get(), quorum->qc->quorumPublicKey);
verifyCount++; verifyCount++;
// We can reconstruct the CRecoveredSig objects from the islock and pass it to the signing manager, which // We can reconstruct the CRecoveredSig objects from the islock and pass it to the signing manager, which
// avoids unnecessary double-verification of the signature. We however only do this when verification here // avoids unnecessary double-verification of the signature. We however only do this when verification here
// turns out to be good (which is checked further down) // turns out to be good (which is checked further down)
if (!sigman.HasRecoveredSigForId(llmqType, id)) { if (!sigman.HasRecoveredSigForId(llmq_params.type, id)) {
recSigs.try_emplace(hash, CRecoveredSig(llmqType, quorum->qc->quorumHash, id, islock->txid, islock->sig)); recSigs.try_emplace(hash, CRecoveredSig(llmq_params.type, quorum->qc->quorumHash, id, islock->txid, islock->sig));
} }
} }
@ -1025,7 +1032,7 @@ std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPend
auto it = recSigs.find(hash); auto it = recSigs.find(hash);
if (it != recSigs.end()) { if (it != recSigs.end()) {
auto recSig = std::make_shared<CRecoveredSig>(std::move(it->second)); auto recSig = std::make_shared<CRecoveredSig>(std::move(it->second));
if (!sigman.HasRecoveredSigForId(llmqType, recSig->getId())) { if (!sigman.HasRecoveredSigForId(llmq_params.type, recSig->getId())) {
LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: passing reconstructed recSig to signing mgr, peer=%d\n", __func__, LogPrint(BCLog::INSTANTSEND, "CInstantSendManager::%s -- txid=%s, islock=%s: passing reconstructed recSig to signing mgr, peer=%d\n", __func__,
islock->txid.ToString(), hash.ToString(), nodeId); islock->txid.ToString(), hash.ToString(), nodeId);
sigman.PushReconstructedRecoveredSig(recSig); sigman.PushReconstructedRecoveredSig(recSig);

View File

@ -284,7 +284,7 @@ private:
bool ProcessPendingInstantSendLocks(); bool ProcessPendingInstantSendLocks();
bool ProcessPendingInstantSendLocks(bool deterministic) LOCKS_EXCLUDED(cs_pendingLocks); bool ProcessPendingInstantSendLocks(bool deterministic) LOCKS_EXCLUDED(cs_pendingLocks);
std::unordered_set<uint256, StaticSaltedHasher> ProcessPendingInstantSendLocks(const Consensus::LLMQType llmqType, std::unordered_set<uint256, StaticSaltedHasher> ProcessPendingInstantSendLocks(const Consensus::LLMQParams& llmq_params,
int signOffset, int signOffset,
const std::unordered_map<uint256, const std::unordered_map<uint256,
std::pair<NodeId, CInstantSendLockPtr>, std::pair<NodeId, CInstantSendLockPtr>,

View File

@ -106,6 +106,11 @@ struct LLMQParams {
int recoveryMembers; int recoveryMembers;
}; };
//static_assert(std::is_trivial_v<Consensus::LLMQParams>, "LLMQParams is not a trivial type");
static_assert(std::is_trivially_copyable_v<Consensus::LLMQParams>, "LLMQParams is not trivially copyable");
//static_assert(std::is_trivially_default_constructible_v<Consensus::LLMQParams>, "LLMQParams is not trivially default constructible");
static_assert(std::is_trivially_assignable_v<Consensus::LLMQParams, Consensus::LLMQParams>, "LLMQParams is not trivially assignable");
static constexpr std::array<LLMQParams, 12> available_llmqs = { static constexpr std::array<LLMQParams, 12> available_llmqs = {

View File

@ -299,7 +299,7 @@ void CQuorumManager::CheckQuorumConnections(const Consensus::LLMQParams& llmqPar
auto connmanQuorumsToDelete = connman.GetMasternodeQuorums(llmqParams.type); auto connmanQuorumsToDelete = connman.GetMasternodeQuorums(llmqParams.type);
// don't remove connections for the currently in-progress DKG round // don't remove connections for the currently in-progress DKG round
if (utils::IsQuorumRotationEnabled(llmqParams.type, pindexNew)) { if (utils::IsQuorumRotationEnabled(llmqParams, pindexNew)) {
int cycleIndexTipHeight = pindexNew->nHeight % llmqParams.dkgInterval; int cycleIndexTipHeight = pindexNew->nHeight % llmqParams.dkgInterval;
int cycleQuorumBaseHeight = pindexNew->nHeight - cycleIndexTipHeight; int cycleQuorumBaseHeight = pindexNew->nHeight - cycleIndexTipHeight;
std::stringstream ss; std::stringstream ss;
@ -371,7 +371,9 @@ CQuorumPtr CQuorumManager::BuildQuorumFromCommitment(const Consensus::LLMQType l
} }
assert(qc->quorumHash == pQuorumBaseBlockIndex->GetBlockHash()); assert(qc->quorumHash == pQuorumBaseBlockIndex->GetBlockHash());
auto quorum = std::make_shared<CQuorum>(llmq::GetLLMQParams(llmqType), blsWorker); const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
auto quorum = std::make_shared<CQuorum>(llmq_params_opt.value(), blsWorker);
auto members = utils::GetAllQuorumMembers(qc->llmqType, pQuorumBaseBlockIndex); auto members = utils::GetAllQuorumMembers(qc->llmqType, pQuorumBaseBlockIndex);
quorum->Init(std::move(qc), pQuorumBaseBlockIndex, minedBlockHash, members); quorum->Init(std::move(qc), pQuorumBaseBlockIndex, minedBlockHash, members);
@ -450,7 +452,7 @@ bool CQuorumManager::RequestQuorumData(CNode* pFrom, Consensus::LLMQType llmqTyp
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- pFrom is neither a verified masternode nor a qwatch connection\n", __func__); LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- pFrom is neither a verified masternode nor a qwatch connection\n", __func__);
return false; return false;
} }
if (!Params().HasLLMQ(llmqType)) { if (!GetLLMQParams(llmqType).has_value()) {
LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Invalid llmqType: %d\n", __func__, static_cast<uint8_t>(llmqType)); LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Invalid llmqType: %d\n", __func__, static_cast<uint8_t>(llmqType));
return false; return false;
} }
@ -523,7 +525,9 @@ std::vector<CQuorumCPtr> CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp
} }
// Get the block indexes of the mined commitments to build the required quorums from // Get the block indexes of the mined commitments to build the required quorums from
std::vector<const CBlockIndex*> pQuorumBaseBlockIndexes{ GetLLMQParams(llmqType).useRotation ? const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
std::vector<const CBlockIndex*> pQuorumBaseBlockIndexes{ llmq_params_opt->useRotation ?
quorumBlockProcessor.GetMinedCommitmentsIndexedUntilBlock(llmqType, pIndexScanCommitments, nScanCommitments) : quorumBlockProcessor.GetMinedCommitmentsIndexedUntilBlock(llmqType, pIndexScanCommitments, nScanCommitments) :
quorumBlockProcessor.GetMinedCommitmentsUntilBlock(llmqType, pIndexScanCommitments, nScanCommitments) quorumBlockProcessor.GetMinedCommitmentsUntilBlock(llmqType, pIndexScanCommitments, nScanCommitments)
}; };
@ -648,7 +652,7 @@ void CQuorumManager::ProcessMessage(CNode* pFrom, const std::string& msg_type, C
} }
} }
if (!Params().HasLLMQ(request.GetLLMQType())) { if (!GetLLMQParams(request.GetLLMQType()).has_value()) {
sendQDATA(CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID); sendQDATA(CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID);
return; return;
} }

View File

@ -158,7 +158,7 @@ class CQuorum
{ {
friend class CQuorumManager; friend class CQuorumManager;
public: public:
const Consensus::LLMQParams& params; const Consensus::LLMQParams params;
CFinalCommitmentPtr qc; CFinalCommitmentPtr qc;
const CBlockIndex* m_quorum_base_block_index{nullptr}; const CBlockIndex* m_quorum_base_block_index{nullptr};
uint256 minedBlockHash; uint256 minedBlockHash;

View File

@ -606,7 +606,7 @@ bool CSigningManager::PreVerifyRecoveredSig(const CQuorumManager& quorum_manager
retBan = false; retBan = false;
auto llmqType = recoveredSig.getLlmqType(); auto llmqType = recoveredSig.getLlmqType();
if (!Params().HasLLMQ(llmqType)) { if (!GetLLMQParams(llmqType).has_value()) {
retBan = true; retBan = true;
return false; return false;
} }
@ -882,7 +882,9 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, CSigShares
// This gives a slight risk of not getting enough shares to recover a signature // This gives a slight risk of not getting enough shares to recover a signature
// But at least it shouldn't be possible to get conflicting recovered signatures // But at least it shouldn't be possible to get conflicting recovered signatures
// 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 // 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
quorum = SelectQuorumForSigning(llmqType, qman, id); const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
quorum = SelectQuorumForSigning(llmq_params_opt.value(), qman, id);
} else { } else {
quorum = qman.GetQuorum(llmqType, quorumHash); quorum = qman.GetQuorum(llmqType, quorumHash);
} }
@ -979,9 +981,9 @@ bool CSigningManager::GetVoteForId(Consensus::LLMQType llmqType, const uint256&
return db.GetVoteForId(llmqType, id, msgHashRet); return db.GetVoteForId(llmqType, id, msgHashRet);
} }
CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, const uint256& selectionHash, int signHeight, int signOffset) CQuorumCPtr CSigningManager::SelectQuorumForSigning(const Consensus::LLMQParams& llmq_params, const CQuorumManager& quorum_manager, const uint256& selectionHash, int signHeight, int signOffset)
{ {
size_t poolSize = GetLLMQParams(llmqType).signingActiveQuorumCount; size_t poolSize = llmq_params.signingActiveQuorumCount;
CBlockIndex* pindexStart; CBlockIndex* pindexStart;
{ {
@ -996,13 +998,13 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
pindexStart = ::ChainActive()[startBlockHeight]; pindexStart = ::ChainActive()[startBlockHeight];
} }
if (utils::IsQuorumRotationEnabled(llmqType, pindexStart)) { if (utils::IsQuorumRotationEnabled(llmq_params, pindexStart)) {
auto quorums = quorum_manager.ScanQuorums(llmqType, pindexStart, poolSize); auto quorums = quorum_manager.ScanQuorums(llmq_params.type, pindexStart, poolSize);
if (quorums.empty()) { if (quorums.empty()) {
return nullptr; return nullptr;
} }
//log2 int //log2 int
int n = std::log2(GetLLMQParams(llmqType).signingActiveQuorumCount); int n = std::log2(llmq_params.signingActiveQuorumCount);
//Extract last 64 bits of selectionHash //Extract last 64 bits of selectionHash
uint64_t b = selectionHash.GetUint64(3); uint64_t b = selectionHash.GetUint64(3);
//Take last n bits of b //Take last n bits of b
@ -1021,7 +1023,7 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
} }
return *itQuorum; return *itQuorum;
} else { } else {
auto quorums = quorum_manager.ScanQuorums(llmqType, pindexStart, poolSize); auto quorums = quorum_manager.ScanQuorums(llmq_params.type, pindexStart, poolSize);
if (quorums.empty()) { if (quorums.empty()) {
return nullptr; return nullptr;
} }
@ -1030,7 +1032,7 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
scores.reserve(quorums.size()); scores.reserve(quorums.size());
for (const auto i : irange::range(quorums.size())) { for (const auto i : irange::range(quorums.size())) {
CHashWriter h(SER_NETWORK, 0); CHashWriter h(SER_NETWORK, 0);
h << llmqType; h << llmq_params.type;
h << quorums[i]->qc->quorumHash; h << quorums[i]->qc->quorumHash;
h << selectionHash; h << selectionHash;
scores.emplace_back(h.GetHash(), i); scores.emplace_back(h.GetHash(), i);
@ -1042,7 +1044,9 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
bool CSigningManager::VerifyRecoveredSig(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, int signedAtHeight, const uint256& id, const uint256& msgHash, const CBLSSignature& sig, const int signOffset) bool CSigningManager::VerifyRecoveredSig(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, int signedAtHeight, const uint256& id, const uint256& msgHash, const CBLSSignature& sig, const int signOffset)
{ {
auto quorum = SelectQuorumForSigning(llmqType, quorum_manager, id, signedAtHeight, signOffset); const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
auto quorum = SelectQuorumForSigning(llmq_params_opt.value(), quorum_manager, id, signedAtHeight, signOffset);
if (!quorum) { if (!quorum) {
return false; return false;
} }

View File

@ -223,7 +223,7 @@ public:
bool GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet) const; bool GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet) const;
static std::vector<CQuorumCPtr> GetActiveQuorumSet(Consensus::LLMQType llmqType, int signHeight); static std::vector<CQuorumCPtr> GetActiveQuorumSet(Consensus::LLMQType llmqType, int signHeight);
static CQuorumCPtr SelectQuorumForSigning(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, const uint256& selectionHash, int signHeight = -1 /*chain tip*/, int signOffset = SIGN_HEIGHT_OFFSET); static CQuorumCPtr SelectQuorumForSigning(const Consensus::LLMQParams& llmq_params, const CQuorumManager& quorum_manager, const uint256& selectionHash, int signHeight = -1 /*chain tip*/, int signOffset = SIGN_HEIGHT_OFFSET);
// Verifies a recovered sig that was signed while the chain tip was at signedAtTip // Verifies a recovered sig that was signed while the chain tip was at signedAtTip
static bool VerifyRecoveredSig(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, int signedAtHeight, const uint256& id, const uint256& msgHash, const CBLSSignature& sig, int signOffset = SIGN_HEIGHT_OFFSET); static bool VerifyRecoveredSig(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, int signedAtHeight, const uint256& id, const uint256& msgHash, const CBLSSignature& sig, int signOffset = SIGN_HEIGHT_OFFSET);

View File

@ -96,7 +96,9 @@ std::string CBatchedSigShares::ToInvString() const
static void InitSession(CSigSharesNodeState::Session& s, const uint256& signHash, CSigBase from) static void InitSession(CSigSharesNodeState::Session& s, const uint256& signHash, CSigBase from)
{ {
const auto& llmq_params = GetLLMQParams((Consensus::LLMQType)from.getLlmqType()); const auto& llmq_params_opt = GetLLMQParams((Consensus::LLMQType)from.getLlmqType());
assert(llmq_params_opt.has_value());
const auto& llmq_params = llmq_params_opt.value();
s.llmqType = from.getLlmqType(); s.llmqType = from.getLlmqType();
s.quorumHash = from.getQuorumHash(); s.quorumHash = from.getQuorumHash();
@ -296,7 +298,7 @@ void CSigSharesManager::ProcessMessage(const CNode* pfrom, const std::string& ms
bool CSigSharesManager::ProcessMessageSigSesAnn(const CNode* pfrom, const CSigSesAnn& ann) bool CSigSharesManager::ProcessMessageSigSesAnn(const CNode* pfrom, const CSigSesAnn& ann)
{ {
auto llmqType = ann.getLlmqType(); auto llmqType = ann.getLlmqType();
if (!Params().HasLLMQ(llmqType)) { if (!GetLLMQParams(llmqType).has_value()) {
return false; return false;
} }
if (ann.getSessionId() == UNINITIALIZED_SESSION_ID || ann.getQuorumHash().IsNull() || ann.getId().IsNull() || ann.getMsgHash().IsNull()) { if (ann.getSessionId() == UNINITIALIZED_SESSION_ID || ann.getQuorumHash().IsNull() || ann.getId().IsNull() || ann.getMsgHash().IsNull()) {
@ -327,7 +329,8 @@ bool CSigSharesManager::ProcessMessageSigSesAnn(const CNode* pfrom, const CSigSe
bool CSigSharesManager::VerifySigSharesInv(Consensus::LLMQType llmqType, const CSigSharesInv& inv) bool CSigSharesManager::VerifySigSharesInv(Consensus::LLMQType llmqType, const CSigSharesInv& inv)
{ {
return inv.inv.size() == size_t(GetLLMQParams(llmqType).size); const auto& llmq_params_opt = GetLLMQParams(llmqType);
return llmq_params_opt.has_value() && (inv.inv.size() == size_t(llmq_params_opt->size));
} }
bool CSigSharesManager::ProcessMessageSigSharesInv(const CNode* pfrom, const CSigSharesInv& inv) bool CSigSharesManager::ProcessMessageSigSharesInv(const CNode* pfrom, const CSigSharesInv& inv)
@ -899,7 +902,9 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std
} }
auto& inv = (*invMap)[signHash]; auto& inv = (*invMap)[signHash];
if (inv.inv.empty()) { if (inv.inv.empty()) {
inv.Init(GetLLMQParams(session.llmqType).size); const auto& llmq_params_opt = GetLLMQParams(session.llmqType);
assert(llmq_params_opt.has_value());
inv.Init(llmq_params_opt->size);
} }
inv.inv[k.second] = true; inv.inv[k.second] = true;
@ -1046,7 +1051,9 @@ void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map<NodeId, st
auto& inv = sigSharesToAnnounce[nodeId][signHash]; auto& inv = sigSharesToAnnounce[nodeId][signHash];
if (inv.inv.empty()) { if (inv.inv.empty()) {
inv.Init(GetLLMQParams(sigShare->getLlmqType()).size); const auto& llmq_params_opt = GetLLMQParams(sigShare->getLlmqType());
assert(llmq_params_opt.has_value());
inv.Init(llmq_params_opt->size);
} }
inv.inv[quorumMember] = true; inv.inv[quorumMember] = true;
session.knows.inv[quorumMember] = true; session.knows.inv[quorumMember] = true;

View File

@ -168,8 +168,10 @@ bool BuildQuorumRotationInfo(const CGetQuorumRotationInfo& request, CQuorumRotat
Consensus::LLMQType llmqType = utils::GetInstantSendLLMQType(qman, blockIndex); Consensus::LLMQType llmqType = utils::GetInstantSendLLMQType(qman, blockIndex);
// Since the returned quorums are in reversed order, the most recent one is at index 0 // Since the returned quorums are in reversed order, the most recent one is at index 0
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType); const auto& llmq_params_opt = GetLLMQParams(llmqType);
const int cycleLength = llmqParams.dkgInterval; assert(llmq_params_opt.has_value());
const int cycleLength = llmq_params_opt->dkgInterval;
constexpr int workDiff = 8; constexpr int workDiff = 8;
const CBlockIndex* hBlockIndex = blockIndex->GetAncestor(blockIndex->nHeight - (blockIndex->nHeight % cycleLength)); const CBlockIndex* hBlockIndex = blockIndex->GetAncestor(blockIndex->nHeight - (blockIndex->nHeight % cycleLength));
@ -307,7 +309,7 @@ bool BuildQuorumRotationInfo(const CGetQuorumRotationInfo& request, CQuorumRotat
} }
response.lastCommitmentPerIndex.push_back(*qc); response.lastCommitmentPerIndex.push_back(*qc);
int quorumCycleStartHeight = obj.second->nHeight - (obj.second->nHeight % llmqParams.dkgInterval); int quorumCycleStartHeight = obj.second->nHeight - (obj.second->nHeight % llmq_params_opt->dkgInterval);
snapshotHeightsNeeded.insert(quorumCycleStartHeight - cycleLength); snapshotHeightsNeeded.insert(quorumCycleStartHeight - cycleLength);
snapshotHeightsNeeded.insert(quorumCycleStartHeight - 2 * cycleLength); snapshotHeightsNeeded.insert(quorumCycleStartHeight - 2 * cycleLength);
snapshotHeightsNeeded.insert(quorumCycleStartHeight - 3 * cycleLength); snapshotHeightsNeeded.insert(quorumCycleStartHeight - 3 * cycleLength);

View File

@ -38,7 +38,7 @@ namespace utils
void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache) void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache)
{ {
for (const Consensus::LLMQParams& params : GetEnabledQuorumParams(pQuorumBaseBlockIndex->pprev)) { for (const Consensus::LLMQParams& params : GetEnabledQuorumParams(pQuorumBaseBlockIndex->pprev)) {
if (IsQuorumRotationEnabled(params.type, pQuorumBaseBlockIndex) && (pQuorumBaseBlockIndex->nHeight % params.dkgInterval == 0)) { if (IsQuorumRotationEnabled(params, pQuorumBaseBlockIndex) && (pQuorumBaseBlockIndex->nHeight % params.dkgInterval == 0)) {
GetAllQuorumMembers(params.type, pQuorumBaseBlockIndex, reset_cache); GetAllQuorumMembers(params.type, pQuorumBaseBlockIndex, reset_cache);
} }
} }
@ -66,7 +66,11 @@ std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqTy
} }
} }
if (IsQuorumRotationEnabled(llmqType, pQuorumBaseBlockIndex)) { const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
const auto& llmq_params = llmq_params_opt.value();
if (IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex)) {
if (LOCK(cs_indexed_members); mapIndexedQuorumMembers.empty()) { if (LOCK(cs_indexed_members); mapIndexedQuorumMembers.empty()) {
InitQuorumsCache(mapIndexedQuorumMembers); InitQuorumsCache(mapIndexedQuorumMembers);
} }
@ -79,9 +83,8 @@ std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqTy
* Quorum Q with quorumIndex is created at height CycleQuorumBaseBlock + quorumIndex * Quorum Q with quorumIndex is created at height CycleQuorumBaseBlock + quorumIndex
*/ */
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType); int quorumIndex = pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval;
int quorumIndex = pQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval; if (quorumIndex >= llmq_params.signingActiveQuorumCount) {
if (quorumIndex >= llmqParams.signingActiveQuorumCount) {
return {}; return {};
} }
int cycleQuorumBaseHeight = pQuorumBaseBlockIndex->nHeight - quorumIndex; int cycleQuorumBaseHeight = pQuorumBaseBlockIndex->nHeight - quorumIndex;
@ -100,7 +103,7 @@ std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqTy
return quorumMembers; return quorumMembers;
} }
auto q = ComputeQuorumMembersByQuarterRotation(llmqType, pCycleQuorumBaseBlockIndex); auto q = ComputeQuorumMembersByQuarterRotation(llmq_params, pCycleQuorumBaseBlockIndex);
LOCK(cs_indexed_members); LOCK(cs_indexed_members);
for (int i = 0; i < static_cast<int>(q.size()); ++i) { for (int i = 0; i < static_cast<int>(q.size()); ++i) {
mapIndexedQuorumMembers[llmqType].insert(std::make_pair(pCycleQuorumBaseBlockIndex->GetBlockHash(), i), q[i]); mapIndexedQuorumMembers[llmqType].insert(std::make_pair(pCycleQuorumBaseBlockIndex->GetBlockHash(), i), q[i]);
@ -120,13 +123,13 @@ std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqT
{ {
auto allMns = deterministicMNManager->GetListForBlock(pQuorumBaseBlockIndex); auto allMns = deterministicMNManager->GetListForBlock(pQuorumBaseBlockIndex);
auto modifier = ::SerializeHash(std::make_pair(llmqType, pQuorumBaseBlockIndex->GetBlockHash())); auto modifier = ::SerializeHash(std::make_pair(llmqType, pQuorumBaseBlockIndex->GetBlockHash()));
return allMns.CalculateQuorum(GetLLMQParams(llmqType).size, modifier); const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
return allMns.CalculateQuorum(llmq_params_opt->size, modifier);
} }
std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRotation(Consensus::LLMQType llmqType, const CBlockIndex* pCycleQuorumBaseBlockIndex) std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRotation(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pCycleQuorumBaseBlockIndex)
{ {
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType);
const int cycleLength = llmqParams.dkgInterval; const int cycleLength = llmqParams.dkgInterval;
assert(pCycleQuorumBaseBlockIndex->nHeight % cycleLength == 0); assert(pCycleQuorumBaseBlockIndex->nHeight % cycleLength == 0);
@ -136,7 +139,7 @@ std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRota
LOCK(deterministicMNManager->cs); LOCK(deterministicMNManager->cs);
const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8); const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8);
auto allMns = deterministicMNManager->GetListForBlock(pWorkBlockIndex); auto allMns = deterministicMNManager->GetListForBlock(pWorkBlockIndex);
LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", static_cast<int>(llmqType), pCycleQuorumBaseBlockIndex->nHeight, allMns.GetValidMNsCount()); LogPrint(BCLog::LLMQ, "ComputeQuorumMembersByQuarterRotation llmqType[%d] nHeight[%d] allMns[%d]\n", static_cast<int>(llmqParams.type), pCycleQuorumBaseBlockIndex->nHeight, allMns.GetValidMNsCount());
PreviousQuorumQuarters previousQuarters = GetPreviousQuorumQuarterMembers(llmqParams, pBlockHMinusCIndex, pBlockHMinus2CIndex, pBlockHMinus3CIndex, pCycleQuorumBaseBlockIndex->nHeight); PreviousQuorumQuarters previousQuarters = GetPreviousQuorumQuarterMembers(llmqParams, pBlockHMinusCIndex, pBlockHMinus2CIndex, pBlockHMinus3CIndex, pCycleQuorumBaseBlockIndex->nHeight);
@ -593,16 +596,16 @@ bool IsQuorumPoseEnabled(Consensus::LLMQType llmqType)
return EvalSpork(llmqType, sporkManager->GetSporkValue(SPORK_23_QUORUM_POSE)); return EvalSpork(llmqType, sporkManager->GetSporkValue(SPORK_23_QUORUM_POSE));
} }
bool IsQuorumRotationEnabled(Consensus::LLMQType llmqType, const CBlockIndex* pindex) bool IsQuorumRotationEnabled(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pindex)
{ {
assert(pindex); assert(pindex);
if (!GetLLMQParams(llmqType).useRotation) { if (!llmqParams.useRotation) {
return false; return false;
} }
LOCK(cs_llmq_vbc); LOCK(cs_llmq_vbc);
int cycleQuorumBaseHeight = pindex->nHeight - (pindex->nHeight % GetLLMQParams(llmqType).dkgInterval); int cycleQuorumBaseHeight = pindex->nHeight - (pindex->nHeight % llmqParams.dkgInterval);
if (cycleQuorumBaseHeight < 1) { if (cycleQuorumBaseHeight < 1) {
return false; return false;
} }
@ -865,7 +868,9 @@ bool IsQuorumActive(Consensus::LLMQType llmqType, const CQuorumManager& qman, co
// sig shares and recovered sigs are only accepted from recent/active quorums // sig shares and recovered sigs are only accepted from recent/active quorums
// we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could // we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could
// fail while we are on the brink of a new quorum // fail while we are on the brink of a new quorum
auto quorums = qman.ScanQuorums(llmqType, GetLLMQParams(llmqType).keepOldConnections); const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
auto quorums = qman.ScanQuorums(llmqType, llmq_params_opt->keepOldConnections);
return ranges::any_of(quorums, [&quorumHash](const auto& q){ return q->qc->quorumHash == quorumHash; }); return ranges::any_of(quorums, [&quorumHash](const auto& q){ return q->qc->quorumHash == quorumHash; });
} }
@ -1025,7 +1030,7 @@ template void InitQuorumsCache<std::map<Consensus::LLMQType, unordered_lru_cache
} // namespace utils } // namespace utils
const Consensus::LLMQParams& GetLLMQParams(Consensus::LLMQType llmqType) const std::optional<Consensus::LLMQParams> GetLLMQParams(Consensus::LLMQType llmqType)
{ {
return Params().GetLLMQ(llmqType); return Params().GetLLMQ(llmqType);
} }

View File

@ -59,7 +59,7 @@ std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqTy
void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache = false); void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache = false);
static std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex); static std::vector<CDeterministicMNCPtr> ComputeQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex);
static std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRotation(Consensus::LLMQType llmqType, const CBlockIndex* pCycleQuorumBaseBlockIndex); static std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRotation(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pCycleQuorumBaseBlockIndex);
static std::vector<std::vector<CDeterministicMNCPtr>> BuildNewQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pQuorumBaseBlockIndex, const PreviousQuorumQuarters& quarters); static std::vector<std::vector<CDeterministicMNCPtr>> BuildNewQuorumQuarterMembers(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pQuorumBaseBlockIndex, const PreviousQuorumQuarters& quarters);
@ -89,7 +89,7 @@ bool IsQuorumTypeEnabledInternal(Consensus::LLMQType llmqType, const CQuorumMana
std::vector<Consensus::LLMQType> GetEnabledQuorumTypes(const CBlockIndex* pindex); std::vector<Consensus::LLMQType> GetEnabledQuorumTypes(const CBlockIndex* pindex);
std::vector<std::reference_wrapper<const Consensus::LLMQParams>> GetEnabledQuorumParams(const CBlockIndex* pindex); std::vector<std::reference_wrapper<const Consensus::LLMQParams>> GetEnabledQuorumParams(const CBlockIndex* pindex);
bool IsQuorumRotationEnabled(Consensus::LLMQType llmqType, const CBlockIndex* pindex); bool IsQuorumRotationEnabled(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pindex);
Consensus::LLMQType GetInstantSendLLMQType(const CQuorumManager& qman, const CBlockIndex* pindex); Consensus::LLMQType GetInstantSendLLMQType(const CQuorumManager& qman, const CBlockIndex* pindex);
Consensus::LLMQType GetInstantSendLLMQType(bool deterministic); Consensus::LLMQType GetInstantSendLLMQType(bool deterministic);
bool IsDIP0024Active(const CBlockIndex* pindex); bool IsDIP0024Active(const CBlockIndex* pindex);
@ -139,7 +139,7 @@ void InitQuorumsCache(CacheType& cache);
} // namespace utils } // namespace utils
const Consensus::LLMQParams& GetLLMQParams(Consensus::LLMQType llmqType); [[ nodiscard ]] const std::optional<Consensus::LLMQParams> GetLLMQParams(Consensus::LLMQType llmqType);
} // namespace llmq } // namespace llmq

View File

@ -70,15 +70,16 @@ static UniValue quorum_list(const JSONRPCRequest& request)
CBlockIndex* pindexTip = WITH_LOCK(cs_main, return ::ChainActive().Tip()); CBlockIndex* pindexTip = WITH_LOCK(cs_main, return ::ChainActive().Tip());
for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) { for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) {
const auto& llmq_params = llmq::GetLLMQParams(type); const auto& llmq_params_opt = llmq::GetLLMQParams(type);
CHECK_NONFATAL(llmq_params_opt.has_value());
UniValue v(UniValue::VARR); UniValue v(UniValue::VARR);
auto quorums = llmq_ctx.qman->ScanQuorums(type, pindexTip, count > -1 ? count : llmq_params.signingActiveQuorumCount); auto quorums = llmq_ctx.qman->ScanQuorums(type, pindexTip, count > -1 ? count : llmq_params_opt->signingActiveQuorumCount);
for (const auto& q : quorums) { for (const auto& q : quorums) {
v.push_back(q->qc->quorumHash.ToString()); v.push_back(q->qc->quorumHash.ToString());
} }
ret.pushKV(std::string(llmq_params.name), v); ret.pushKV(std::string(llmq_params_opt->name), v);
} }
return ret; return ret;
@ -135,7 +136,9 @@ static UniValue quorum_list_extended(const JSONRPCRequest& request)
CBlockIndex* pblockindex = nHeight != -1 ? WITH_LOCK(cs_main, return ::ChainActive()[nHeight]) : WITH_LOCK(cs_main, return ::ChainActive().Tip()); CBlockIndex* pblockindex = nHeight != -1 ? WITH_LOCK(cs_main, return ::ChainActive()[nHeight]) : WITH_LOCK(cs_main, return ::ChainActive().Tip());
for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pblockindex)) { for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pblockindex)) {
const auto& llmq_params = llmq::GetLLMQParams(type); const auto& llmq_params_opt = llmq::GetLLMQParams(type);
CHECK_NONFATAL(llmq_params_opt.has_value());
const auto& llmq_params = llmq_params_opt.value();
UniValue v(UniValue::VARR); UniValue v(UniValue::VARR);
auto quorums = llmq_ctx.qman->ScanQuorums(type, pblockindex, llmq_params.signingActiveQuorumCount); auto quorums = llmq_ctx.qman->ScanQuorums(type, pblockindex, llmq_params.signingActiveQuorumCount);
@ -222,7 +225,7 @@ static UniValue quorum_info(const JSONRPCRequest& request)
quorum_info_help(request); quorum_info_help(request);
Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType"); Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType");
if (!Params().HasLLMQ(llmqType)) { if (!llmq::GetLLMQParams(llmqType).has_value()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type");
} }
@ -282,8 +285,10 @@ static UniValue quorum_dkgstatus(const JSONRPCRequest& request)
UniValue minableCommitments(UniValue::VARR); UniValue minableCommitments(UniValue::VARR);
UniValue quorumArrConnections(UniValue::VARR); UniValue quorumArrConnections(UniValue::VARR);
for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) { for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) {
const auto& llmq_params = llmq::GetLLMQParams(type); const auto& llmq_params_opt = llmq::GetLLMQParams(type);
bool rotation_enabled = llmq::utils::IsQuorumRotationEnabled(type, pindexTip); CHECK_NONFATAL(llmq_params_opt.has_value());
const auto& llmq_params = llmq_params_opt.value();
bool rotation_enabled = llmq::utils::IsQuorumRotationEnabled(llmq_params, pindexTip);
size_t quorums_num = rotation_enabled ? llmq_params.signingActiveQuorumCount : 1; size_t quorums_num = rotation_enabled ? llmq_params.signingActiveQuorumCount : 1;
for (int quorumIndex = 0; quorumIndex < quorums_num; ++quorumIndex) { for (int quorumIndex = 0; quorumIndex < quorums_num; ++quorumIndex) {
@ -386,12 +391,13 @@ static UniValue quorum_memberof(const JSONRPCRequest& request)
UniValue result(UniValue::VARR); UniValue result(UniValue::VARR);
for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) { for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) {
const auto& llmq_params = llmq::GetLLMQParams(type); const auto& llmq_params_opt = llmq::GetLLMQParams(type);
size_t count = llmq_params.signingActiveQuorumCount; CHECK_NONFATAL(llmq_params_opt.has_value());
size_t count = llmq_params_opt->signingActiveQuorumCount;
if (scanQuorumsCount != -1) { if (scanQuorumsCount != -1) {
count = (size_t)scanQuorumsCount; count = (size_t)scanQuorumsCount;
} }
auto quorums = llmq_ctx.qman->ScanQuorums(llmq_params.type, count); auto quorums = llmq_ctx.qman->ScanQuorums(llmq_params_opt->type, count);
for (auto& quorum : quorums) { for (auto& quorum : quorums) {
if (quorum->IsMember(dmn->proTxHash)) { if (quorum->IsMember(dmn->proTxHash)) {
auto json = BuildQuorumInfo(quorum, false, false); auto json = BuildQuorumInfo(quorum, false, false);
@ -508,7 +514,8 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
LLMQContext& llmq_ctx = EnsureLLMQContext(request.context); LLMQContext& llmq_ctx = EnsureLLMQContext(request.context);
Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType"); Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType");
if (!Params().HasLLMQ(llmqType)) { const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
if (!llmq_params_opt.has_value()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type");
} }
@ -530,7 +537,7 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
llmq::CQuorumCPtr pQuorum; llmq::CQuorumCPtr pQuorum;
if (quorumHash.IsNull()) { if (quorumHash.IsNull()) {
pQuorum = llmq_ctx.sigman->SelectQuorumForSigning(llmqType, *llmq_ctx.qman, id); pQuorum = llmq_ctx.sigman->SelectQuorumForSigning(llmq_params_opt.value(), *llmq_ctx.qman, id);
} else { } else {
pQuorum = llmq_ctx.qman->GetQuorum(llmqType, quorumHash); pQuorum = llmq_ctx.qman->GetQuorum(llmqType, quorumHash);
} }
@ -568,7 +575,7 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
signHeight = ParseInt32V(request.params[5], "signHeight"); signHeight = ParseInt32V(request.params[5], "signHeight");
} }
// First check against the current active set, if it fails check against the last active set // First check against the current active set, if it fails check against the last active set
int signOffset{llmq::GetLLMQParams(llmqType).dkgInterval}; int signOffset{llmq_params_opt->dkgInterval};
return llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, 0) || return llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, 0) ||
llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, signOffset); llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, signOffset);
} else { } else {
@ -619,7 +626,8 @@ static UniValue quorum_selectquorum(const JSONRPCRequest& request)
quorum_selectquorum_help(request); quorum_selectquorum_help(request);
Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType"); Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType");
if (!Params().HasLLMQ(llmqType)) { const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
if (!llmq_params_opt.has_value()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type");
} }
@ -628,7 +636,7 @@ static UniValue quorum_selectquorum(const JSONRPCRequest& request)
UniValue ret(UniValue::VOBJ); UniValue ret(UniValue::VOBJ);
LLMQContext& llmq_ctx = EnsureLLMQContext(request.context); LLMQContext& llmq_ctx = EnsureLLMQContext(request.context);
auto quorum = llmq_ctx.sigman->SelectQuorumForSigning(llmqType, *llmq_ctx.qman, id); auto quorum = llmq_ctx.sigman->SelectQuorumForSigning(llmq_params_opt.value(), *llmq_ctx.qman, id);
if (!quorum) { if (!quorum) {
throw JSONRPCError(RPC_MISC_ERROR, "no quorums active"); throw JSONRPCError(RPC_MISC_ERROR, "no quorums active");
} }
@ -944,7 +952,9 @@ static UniValue verifyislock(const JSONRPCRequest& request)
auto llmqType = llmq::utils::GetInstantSendLLMQType(*llmq_ctx.qman, pBlockIndex); auto llmqType = llmq::utils::GetInstantSendLLMQType(*llmq_ctx.qman, pBlockIndex);
// First check against the current active set, if it fails check against the last active set // First check against the current active set, if it fails check against the last active set
int signOffset{llmq::GetLLMQParams(llmqType).dkgInterval}; const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
CHECK_NONFATAL(llmq_params_opt.has_value());
int signOffset{llmq_params_opt->dkgInterval};
return llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, 0) || return llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, 0) ||
llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, signOffset); llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, signOffset);
} }