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)
{
assert(!HasLLMQ(llmqType));
assert(!GetLLMQ(llmqType).has_value());
for (const auto& llmq_param : Consensus::available_llmqs) {
if (llmq_param.type == llmqType) {
consensus.llmqs.push_back(llmq_param);
@ -121,25 +121,14 @@ void CChainParams::AddLLMQ(Consensus::LLMQType llmqType)
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) {
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));
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;
return std::nullopt;
}
/**
@ -1231,7 +1220,10 @@ void CDevNetParams::UpdateDevnetLLMQChainLocksFromArgs(const ArgsManager& args)
{
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;
for (const auto& params : consensus.llmqs) {
@ -1253,7 +1245,10 @@ void CDevNetParams::UpdateDevnetLLMQInstantSendFromArgs(const ArgsManager& args)
{
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;
for (const auto& params : consensus.llmqs) {
@ -1275,7 +1270,10 @@ void CDevNetParams::UpdateDevnetLLMQInstantSendDIP0024FromArgs(const ArgsManager
{
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;
for (const auto& params : consensus.llmqs) {

View File

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

View File

@ -188,7 +188,9 @@ auto CachedGetQcHashesQcIndexedHashes(const CBlockIndex* pindexPrev, const llmq:
qcIndexedHashes_cached.clear();
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];
vec_hashes.reserve(vecBlockIndexes.size());
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
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);
if (llmq::utils::IsQuorumRotationEnabled(qc.commitment.llmqType, pindexPrev)) {
if (llmq::utils::IsQuorumRotationEnabled(llmq_params, pindexPrev)) {
auto& map_indexed_hashes = qcIndexedHashes[qc.commitment.llmqType];
map_indexed_hashes[qc.commitment.quorumIndex] = qcHash;
} else {
const auto& llmq_params = llmq::GetLLMQParams(qc.commitment.llmqType);
auto& vec_hashes = qcHashes[llmq_params.type];
if (vec_hashes.size() == size_t(llmq_params.signingActiveQuorumCount)) {
// 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));
for (const auto& [llmqType, vec_hashes] : qcHashes) {
const auto& llmq_params = llmq::GetLLMQParams(llmqType);
if (vec_hashes.size() > size_t(llmq_params.signingActiveQuorumCount)) {
const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType);
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");
}
// 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");
}
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 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);
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

View File

@ -25,7 +25,9 @@ bool MNHFTx::Verify(const CBlockIndex* pQuorumIndex) const
}
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));
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");
}
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");
}

View File

@ -58,7 +58,8 @@ void CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_view m
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__,
uint8_t(qc.llmqType), peer.GetId());
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
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) {
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());
Misbehaving(peer.GetId(), 100);
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__,
qc.quorumHash.ToString(), peer.GetId());
// 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) {
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);
}
}
@ -209,7 +210,12 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
{
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);
@ -263,7 +269,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH
return true;
}
bool rotation_enabled = utils::IsQuorumRotationEnabled(llmq_params.type, pQuorumBaseBlockIndex);
bool rotation_enabled = utils::IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex);
if (rotation_enabled) {
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)));
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)));
} else {
evoDb.Erase(BuildInversedHeightKey(qc.llmqType, pindex->nHeight));
@ -372,7 +381,9 @@ bool CQuorumBlockProcessor::UpgradeDB()
}
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()));
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);
} else {
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");
}
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)
if (!utils::IsQuorumRotationEnabled(qc.commitment.llmqType, pindex)) {
if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) {
if (ret.count(qc.commitment.llmqType) != 0) {
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);
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 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
{
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;
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);
if (q.has_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) {
auto& v = ret[params.type];
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::transform(commitments.begin(), commitments.end(), std::back_inserter(v),
[](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);
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;
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
{
if (nVersion == 0 || nVersion != (utils::IsQuorumRotationEnabled(llmqType, pQuorumBaseBlockIndex) ? INDEXED_QUORUM_VERSION : CURRENT_VERSION)) {
LogPrintfFinalCommitment("q[%s] invalid nVersion=%d\n", quorumHash.ToString(), nVersion);
return false;
}
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));
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) {
LogPrintfFinalCommitment("q[%s] invalid quorumHash\n", quorumHash.ToString());
@ -138,12 +139,13 @@ bool CFinalCommitment::Verify(const CBlockIndex* pQuorumBaseBlockIndex, bool che
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));
return false;
}
if (!IsNull() || !VerifySizes(GetLLMQParams(llmqType))) {
if (!IsNull() || !VerifySizes(llmq_params_opt.value())) {
return false;
}
@ -170,10 +172,16 @@ bool CheckLLMQCommitment(const CTransaction& tx, const CBlockIndex* pindexPrev,
LogPrintfFinalCommitment("h[%d] GetTxPayload failed\n", pindexPrev->nHeight);
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)) {
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];
}
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");
}
if (!Params().HasLLMQ(qcTx.commitment.llmqType)) {
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-qc-type");
}
if (qcTx.commitment.IsNull()) {
if (!qcTx.commitment.VerifyNull()) {
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);
if (!Params().HasLLMQ(llmqType) || quorumHash.IsNull()) {
if (!GetLLMQParams(llmqType).has_value() || quorumHash.IsNull()) {
return ret;
}
@ -117,11 +117,12 @@ UniValue CDKGDebugStatus::ToJson(int detailLevel) const
// TODO Support array of sessions
UniValue sessionsArrJson(UniValue::VARR);
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;
}
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("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__);
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;
const CBlockIndex* pCycleQuorumBaseBlockIndex = m_quorum_base_block_index->GetAncestor(cycleQuorumBaseHeight);
std::stringstream ss;
@ -1206,7 +1206,7 @@ std::vector<CFinalCommitment> CDKGSession::FinalizeCommitments()
fqc.quorumPublicKey = first.quorumPublicKey;
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.quorumIndex = quorumIndex;
} else {

View File

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

View File

@ -84,7 +84,7 @@ void CDKGSessionHandler::UpdatedBlockTip(const CBlockIndex* pindexNew)
{
//AssertLockNotHeld(cs_main);
//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;
}
LOCK(cs);

View File

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

View File

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

View File

@ -706,8 +706,10 @@ void CInstantSendManager::TrySignInstantSendLock(const CTransaction& tx)
// compute and set cycle hash if islock is deterministic
if (islock.IsDeterministic()) {
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt);
LOCK(cs_main);
const auto dkgInterval = GetLLMQParams(llmqType).dkgInterval;
const auto dkgInterval = llmq_params_opt->dkgInterval;
const auto quorumHeight = ::ChainActive().Height() - (::ChainActive().Height() % dkgInterval);
islock.cycleHash = ::ChainActive()[quorumHeight]->GetBlockHash();
}
@ -804,7 +806,9 @@ void CInstantSendManager::ProcessMessageInstantSendLock(const CNode* pfrom, cons
// Deterministic islocks MUST use rotation based llmq
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));
return;
}
@ -905,10 +909,13 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks(bool deterministic)
//TODO Investigate if leaving this is ok
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
auto badISLocks = ProcessPendingInstantSendLocks(llmqType, 0, pend, false);
auto badISLocks = ProcessPendingInstantSendLocks(llmq_params, 0, pend, false);
if (!badISLocks.empty()) {
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
ProcessPendingInstantSendLocks(llmqType, dkgInterval, pend, true);
ProcessPendingInstantSendLocks(llmq_params, dkgInterval, pend, true);
}
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);
std::unordered_map<uint256, CRecoveredSig, StaticSaltedHasher> recSigs;
@ -951,7 +958,7 @@ std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPend
auto id = islock->GetRequestId();
// 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++;
continue;
}
@ -966,26 +973,26 @@ std::unordered_set<uint256, StaticSaltedHasher> CInstantSendManager::ProcessPend
continue;
}
const auto dkgInterval = GetLLMQParams(llmqType).dkgInterval;
const auto dkgInterval = llmq_params.dkgInterval;
if (blockIndex->nHeight + dkgInterval < ::ChainActive().Height()) {
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) {
// should not happen, but if one fails to select, all others will also fail to select
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);
verifyCount++;
// 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
// turns out to be good (which is checked further down)
if (!sigman.HasRecoveredSigForId(llmqType, id)) {
recSigs.try_emplace(hash, CRecoveredSig(llmqType, quorum->qc->quorumHash, id, islock->txid, islock->sig));
if (!sigman.HasRecoveredSigForId(llmq_params.type, id)) {
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);
if (it != recSigs.end()) {
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__,
islock->txid.ToString(), hash.ToString(), nodeId);
sigman.PushReconstructedRecoveredSig(recSig);

View File

@ -284,7 +284,7 @@ private:
bool ProcessPendingInstantSendLocks();
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,
const std::unordered_map<uint256,
std::pair<NodeId, CInstantSendLockPtr>,

View File

@ -106,6 +106,11 @@ struct LLMQParams {
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 = {

View File

@ -299,7 +299,7 @@ void CQuorumManager::CheckQuorumConnections(const Consensus::LLMQParams& llmqPar
auto connmanQuorumsToDelete = connman.GetMasternodeQuorums(llmqParams.type);
// 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 cycleQuorumBaseHeight = pindexNew->nHeight - cycleIndexTipHeight;
std::stringstream ss;
@ -371,7 +371,9 @@ CQuorumPtr CQuorumManager::BuildQuorumFromCommitment(const Consensus::LLMQType l
}
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);
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__);
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));
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
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.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);
return;
}

View File

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

View File

@ -606,7 +606,7 @@ bool CSigningManager::PreVerifyRecoveredSig(const CQuorumManager& quorum_manager
retBan = false;
auto llmqType = recoveredSig.getLlmqType();
if (!Params().HasLLMQ(llmqType)) {
if (!GetLLMQParams(llmqType).has_value()) {
retBan = true;
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
// 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
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 {
quorum = qman.GetQuorum(llmqType, quorumHash);
}
@ -979,9 +981,9 @@ bool CSigningManager::GetVoteForId(Consensus::LLMQType llmqType, const uint256&
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;
{
@ -996,13 +998,13 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
pindexStart = ::ChainActive()[startBlockHeight];
}
if (utils::IsQuorumRotationEnabled(llmqType, pindexStart)) {
auto quorums = quorum_manager.ScanQuorums(llmqType, pindexStart, poolSize);
if (utils::IsQuorumRotationEnabled(llmq_params, pindexStart)) {
auto quorums = quorum_manager.ScanQuorums(llmq_params.type, pindexStart, poolSize);
if (quorums.empty()) {
return nullptr;
}
//log2 int
int n = std::log2(GetLLMQParams(llmqType).signingActiveQuorumCount);
int n = std::log2(llmq_params.signingActiveQuorumCount);
//Extract last 64 bits of selectionHash
uint64_t b = selectionHash.GetUint64(3);
//Take last n bits of b
@ -1021,7 +1023,7 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
}
return *itQuorum;
} else {
auto quorums = quorum_manager.ScanQuorums(llmqType, pindexStart, poolSize);
auto quorums = quorum_manager.ScanQuorums(llmq_params.type, pindexStart, poolSize);
if (quorums.empty()) {
return nullptr;
}
@ -1030,7 +1032,7 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(Consensus::LLMQType llmqType
scores.reserve(quorums.size());
for (const auto i : irange::range(quorums.size())) {
CHashWriter h(SER_NETWORK, 0);
h << llmqType;
h << llmq_params.type;
h << quorums[i]->qc->quorumHash;
h << selectionHash;
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)
{
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) {
return false;
}

View File

@ -223,7 +223,7 @@ public:
bool GetVoteForId(Consensus::LLMQType llmqType, const uint256& id, uint256& msgHashRet) const;
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
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)
{
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.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)
{
auto llmqType = ann.getLlmqType();
if (!Params().HasLLMQ(llmqType)) {
if (!GetLLMQParams(llmqType).has_value()) {
return false;
}
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)
{
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)
@ -899,7 +902,9 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_map<NodeId, std
}
auto& inv = (*invMap)[signHash];
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;
@ -1046,7 +1051,9 @@ void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_map<NodeId, st
auto& inv = sigSharesToAnnounce[nodeId][signHash];
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;
session.knows.inv[quorumMember] = true;

View File

@ -168,8 +168,10 @@ bool BuildQuorumRotationInfo(const CGetQuorumRotationInfo& request, CQuorumRotat
Consensus::LLMQType llmqType = utils::GetInstantSendLLMQType(qman, blockIndex);
// Since the returned quorums are in reversed order, the most recent one is at index 0
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType);
const int cycleLength = llmqParams.dkgInterval;
const auto& llmq_params_opt = GetLLMQParams(llmqType);
assert(llmq_params_opt.has_value());
const int cycleLength = llmq_params_opt->dkgInterval;
constexpr int workDiff = 8;
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);
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 - 2 * cycleLength);
snapshotHeightsNeeded.insert(quorumCycleStartHeight - 3 * cycleLength);

View File

@ -38,7 +38,7 @@ namespace utils
void PreComputeQuorumMembers(const CBlockIndex* pQuorumBaseBlockIndex, bool reset_cache)
{
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);
}
}
@ -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()) {
InitQuorumsCache(mapIndexedQuorumMembers);
}
@ -79,9 +83,8 @@ std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqTy
* Quorum Q with quorumIndex is created at height CycleQuorumBaseBlock + quorumIndex
*/
const Consensus::LLMQParams& llmqParams = GetLLMQParams(llmqType);
int quorumIndex = pQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval;
if (quorumIndex >= llmqParams.signingActiveQuorumCount) {
int quorumIndex = pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval;
if (quorumIndex >= llmq_params.signingActiveQuorumCount) {
return {};
}
int cycleQuorumBaseHeight = pQuorumBaseBlockIndex->nHeight - quorumIndex;
@ -100,7 +103,7 @@ std::vector<CDeterministicMNCPtr> GetAllQuorumMembers(Consensus::LLMQType llmqTy
return quorumMembers;
}
auto q = ComputeQuorumMembersByQuarterRotation(llmqType, pCycleQuorumBaseBlockIndex);
auto q = ComputeQuorumMembersByQuarterRotation(llmq_params, pCycleQuorumBaseBlockIndex);
LOCK(cs_indexed_members);
for (int i = 0; i < static_cast<int>(q.size()); ++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 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;
assert(pCycleQuorumBaseBlockIndex->nHeight % cycleLength == 0);
@ -136,7 +139,7 @@ std::vector<std::vector<CDeterministicMNCPtr>> ComputeQuorumMembersByQuarterRota
LOCK(deterministicMNManager->cs);
const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8);
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);
@ -593,16 +596,16 @@ bool IsQuorumPoseEnabled(Consensus::LLMQType llmqType)
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);
if (!GetLLMQParams(llmqType).useRotation) {
if (!llmqParams.useRotation) {
return false;
}
LOCK(cs_llmq_vbc);
int cycleQuorumBaseHeight = pindex->nHeight - (pindex->nHeight % GetLLMQParams(llmqType).dkgInterval);
int cycleQuorumBaseHeight = pindex->nHeight - (pindex->nHeight % llmqParams.dkgInterval);
if (cycleQuorumBaseHeight < 1) {
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
// 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
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; });
}
@ -1025,7 +1030,7 @@ template void InitQuorumsCache<std::map<Consensus::LLMQType, unordered_lru_cache
} // namespace utils
const Consensus::LLMQParams& GetLLMQParams(Consensus::LLMQType llmqType)
const std::optional<Consensus::LLMQParams> GetLLMQParams(Consensus::LLMQType 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);
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);
@ -89,7 +89,7 @@ bool IsQuorumTypeEnabledInternal(Consensus::LLMQType llmqType, const CQuorumMana
std::vector<Consensus::LLMQType> GetEnabledQuorumTypes(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(bool deterministic);
bool IsDIP0024Active(const CBlockIndex* pindex);
@ -139,7 +139,7 @@ void InitQuorumsCache(CacheType& cache);
} // namespace utils
const Consensus::LLMQParams& GetLLMQParams(Consensus::LLMQType llmqType);
[[ nodiscard ]] const std::optional<Consensus::LLMQParams> GetLLMQParams(Consensus::LLMQType llmqType);
} // namespace llmq

View File

@ -70,15 +70,16 @@ static UniValue quorum_list(const JSONRPCRequest& request)
CBlockIndex* pindexTip = WITH_LOCK(cs_main, return ::ChainActive().Tip());
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);
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) {
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;
@ -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());
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);
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);
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");
}
@ -282,8 +285,10 @@ static UniValue quorum_dkgstatus(const JSONRPCRequest& request)
UniValue minableCommitments(UniValue::VARR);
UniValue quorumArrConnections(UniValue::VARR);
for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) {
const auto& llmq_params = llmq::GetLLMQParams(type);
bool rotation_enabled = llmq::utils::IsQuorumRotationEnabled(type, pindexTip);
const auto& llmq_params_opt = llmq::GetLLMQParams(type);
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;
for (int quorumIndex = 0; quorumIndex < quorums_num; ++quorumIndex) {
@ -386,12 +391,13 @@ static UniValue quorum_memberof(const JSONRPCRequest& request)
UniValue result(UniValue::VARR);
for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) {
const auto& llmq_params = llmq::GetLLMQParams(type);
size_t count = llmq_params.signingActiveQuorumCount;
const auto& llmq_params_opt = llmq::GetLLMQParams(type);
CHECK_NONFATAL(llmq_params_opt.has_value());
size_t count = llmq_params_opt->signingActiveQuorumCount;
if (scanQuorumsCount != -1) {
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) {
if (quorum->IsMember(dmn->proTxHash)) {
auto json = BuildQuorumInfo(quorum, false, false);
@ -508,7 +514,8 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
LLMQContext& llmq_ctx = EnsureLLMQContext(request.context);
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");
}
@ -530,7 +537,7 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request)
llmq::CQuorumCPtr pQuorum;
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 {
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");
}
// 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) ||
llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, msgHash, sig, signOffset);
} else {
@ -619,7 +626,8 @@ static UniValue quorum_selectquorum(const JSONRPCRequest& request)
quorum_selectquorum_help(request);
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");
}
@ -628,7 +636,7 @@ static UniValue quorum_selectquorum(const JSONRPCRequest& request)
UniValue ret(UniValue::VOBJ);
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) {
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);
// 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) ||
llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, signOffset);
}