@@ -342,9 +342,13 @@ void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const Consensu
342342std::vector<QuorumMembers> BuildNewQuorumQuarterMembers (const Consensus::LLMQParams& llmqParams,
343343 const llmq::UtilParameters& util_params,
344344 const CDeterministicMNList& allMns,
345- const PreviousQuorumQuarters& previousQuarters)
345+ const PreviousQuorumQuarters& previousQuarters,
346+ const uint256& modifier,
347+ gsl::not_null<const CBlockIndex*> pDeploymentIndex,
348+ int cycleBaseHeight,
349+ bool storeSnapshot)
346350{
347- if (!llmqParams.useRotation || util_params. m_base_index -> nHeight % llmqParams.dkgInterval != 0 ) {
351+ if (!llmqParams.useRotation || cycleBaseHeight % llmqParams.dkgInterval != 0 ) {
348352 ASSERT_IF_DEBUG (false );
349353 return {};
350354 }
@@ -354,7 +358,6 @@ std::vector<QuorumMembers> BuildNewQuorumQuarterMembers(const Consensus::LLMQPar
354358
355359 size_t quorumSize = static_cast <size_t >(llmqParams.size );
356360 auto quarterSize{quorumSize / 4 };
357- const auto modifier = GetHashModifier (llmqParams, util_params.m_chainman .GetConsensus (), util_params.m_base_index );
358361
359362 if (allMns.GetCounts ().enabled () < quarterSize) {
360363 return quarterQuorumMembers;
@@ -363,7 +366,7 @@ std::vector<QuorumMembers> BuildNewQuorumQuarterMembers(const Consensus::LLMQPar
363366 auto MnsUsedAtH = CDeterministicMNList ();
364367 std::vector<CDeterministicMNList> MnsUsedAtHIndexed{nQuorums};
365368
366- bool skipRemovedMNs = DeploymentActiveAfter (util_params. m_base_index , util_params.m_chainman .GetConsensus (),
369+ bool skipRemovedMNs = DeploymentActiveAfter (pDeploymentIndex. get () , util_params.m_chainman .GetConsensus (),
367370 Consensus::DEPLOYMENT_V19 ) ||
368371 (util_params.m_chainman .GetParams ().NetworkIDString () == CBaseChainParams::TESTNET );
369372
@@ -404,7 +407,7 @@ std::vector<QuorumMembers> BuildNewQuorumQuarterMembers(const Consensus::LLMQPar
404407 }
405408
406409 if (LogAcceptDebug (BCLog::LLMQ )) {
407- LogPrint (BCLog::LLMQ , " %s h[%d] sortedCombinedMns[%s]\n " , __func__, util_params. m_base_index -> nHeight ,
410+ LogPrint (BCLog::LLMQ , " %s h[%d] sortedCombinedMns[%s]\n " , __func__, cycleBaseHeight ,
408411 ToString (sortedCombinedMnsList));
409412 }
410413
@@ -450,14 +453,31 @@ std::vector<QuorumMembers> BuildNewQuorumQuarterMembers(const Consensus::LLMQPar
450453 }
451454 }
452455
453- llmq::CQuorumSnapshot quorumSnapshot{};
454- BuildQuorumSnapshot (llmqParams, util_params.m_chainman .GetConsensus (), allMns, MnsUsedAtH, sortedCombinedMnsList,
455- quorumSnapshot, skipList, util_params.m_base_index );
456- util_params.m_qsnapman .StoreSnapshotForBlock (llmqParams.type , util_params.m_base_index , quorumSnapshot);
456+ if (storeSnapshot) {
457+ llmq::CQuorumSnapshot quorumSnapshot{};
458+ BuildQuorumSnapshot (llmqParams, util_params.m_chainman .GetConsensus (), allMns, MnsUsedAtH, sortedCombinedMnsList,
459+ quorumSnapshot, skipList, util_params.m_base_index );
460+ util_params.m_qsnapman .StoreSnapshotForBlock (llmqParams.type , util_params.m_base_index , quorumSnapshot);
461+ }
457462
458463 return quarterQuorumMembers;
459464}
460465
466+ std::vector<QuorumMembers> BuildNewQuorumQuarterMembers (const Consensus::LLMQParams& llmqParams,
467+ const llmq::UtilParameters& util_params,
468+ const CDeterministicMNList& allMns,
469+ const PreviousQuorumQuarters& previousQuarters)
470+ {
471+ if (!llmqParams.useRotation || util_params.m_base_index ->nHeight % llmqParams.dkgInterval != 0 ) {
472+ ASSERT_IF_DEBUG (false );
473+ return {};
474+ }
475+ const auto modifier = GetHashModifier (llmqParams, util_params.m_chainman .GetConsensus (), util_params.m_base_index );
476+ return BuildNewQuorumQuarterMembers (llmqParams, util_params, allMns, previousQuarters, modifier,
477+ util_params.m_base_index , util_params.m_base_index ->nHeight ,
478+ /* storeSnapshot=*/ true );
479+ }
480+
461481std::vector<QuorumMembers> ComputeQuorumMembersByQuarterRotation (const Consensus::LLMQParams& llmqParams,
462482 const llmq::UtilParameters& util_params)
463483{
@@ -597,6 +617,85 @@ std::vector<CDeterministicMNCPtr> ComputeNonRotatedQuorumMembersFromWorkBlock(
597617 return CalculateQuorum (mn_list, modifier, llmq_params.size , EvoOnly);
598618}
599619
620+ std::optional<std::vector<CDeterministicMNCPtr>> ComputeRotatedQuorumMembersFromWorkBlock (
621+ Consensus::LLMQType llmqType, const UtilParameters& util_params,
622+ gsl::not_null<const CBlockIndex*> pWorkBlockIndex, int quorumHeight)
623+ {
624+ const auto & llmq_params_opt = util_params.m_chainman .GetParams ().GetLLMQ (llmqType);
625+ if (!llmq_params_opt.has_value ()) {
626+ ASSERT_IF_DEBUG (false );
627+ return std::nullopt ;
628+ }
629+ const auto & llmq_params = llmq_params_opt.value ();
630+ if (!llmq_params.useRotation ) {
631+ ASSERT_IF_DEBUG (false );
632+ return std::nullopt ;
633+ }
634+
635+ const int quorumIndex{quorumHeight % llmq_params.dkgInterval };
636+ if (quorumIndex < 0 || quorumIndex >= llmq_params.signingActiveQuorumCount ) {
637+ ASSERT_IF_DEBUG (false );
638+ return std::nullopt ;
639+ }
640+ const int cycleBaseHeight{quorumHeight - quorumIndex};
641+ if (cycleBaseHeight % llmq_params.dkgInterval != 0 ||
642+ pWorkBlockIndex->nHeight != cycleBaseHeight - llmq::WORK_DIFF_DEPTH ) {
643+ ASSERT_IF_DEBUG (false );
644+ return std::nullopt ;
645+ }
646+
647+ if (!DeploymentActiveAfter (pWorkBlockIndex.get (), util_params.m_chainman .GetConsensus (), Consensus::DEPLOYMENT_V20 )) {
648+ // pre-v20 modifier calculation needs the future cycle base block context, which isn't known yet.
649+ return std::nullopt ;
650+ }
651+
652+ const auto nQuorums{static_cast <size_t >(llmq_params.signingActiveQuorumCount )};
653+ PreviousQuorumQuarters previousQuarters (nQuorums);
654+ auto prev_cycles{previousQuarters.GetCycles ()};
655+ for (size_t idx{0 }; idx < prev_cycles.size (); idx++) {
656+ const int previousCycleHeight{cycleBaseHeight - llmq_params.dkgInterval * static_cast <int >(idx + 1 )};
657+ if (previousCycleHeight < 0 ) {
658+ return std::nullopt ;
659+ }
660+ prev_cycles[idx]->m_cycle_index = pWorkBlockIndex->GetAncestor (previousCycleHeight);
661+ if (prev_cycles[idx]->m_cycle_index == nullptr ) {
662+ return std::nullopt ;
663+ }
664+ if (auto opt_snap = util_params.m_qsnapman .GetSnapshotForBlock (llmq_params.type , prev_cycles[idx]->m_cycle_index );
665+ opt_snap.has_value ()) {
666+ prev_cycles[idx]->m_snap = opt_snap.value ();
667+ } else {
668+ return std::nullopt ;
669+ }
670+ prev_cycles[idx]->m_members = GetQuorumQuarterMembersBySnapshot (llmq_params, util_params.m_dmnman ,
671+ util_params.m_chainman .GetConsensus (),
672+ prev_cycles[idx]->m_cycle_index ,
673+ prev_cycles[idx]->m_snap ,
674+ cycleBaseHeight);
675+ }
676+
677+ CDeterministicMNList allMns = util_params.m_dmnman .GetListForBlock (pWorkBlockIndex);
678+ const auto modifier = GetHashModifierFromWorkBlock (llmq_params, pWorkBlockIndex.get ());
679+ auto newQuarterMembers = BuildNewQuorumQuarterMembers (llmq_params, util_params, allMns, previousQuarters,
680+ modifier, pWorkBlockIndex, cycleBaseHeight,
681+ /* storeSnapshot=*/ false );
682+ if (newQuarterMembers.size () != nQuorums) {
683+ return std::nullopt ;
684+ }
685+
686+ QuorumMembers quorumMembers;
687+ for (auto * prev_cycle : prev_cycles | std::views::reverse) {
688+ quorumMembers.insert (quorumMembers.end (),
689+ prev_cycle->m_members [quorumIndex].begin (),
690+ prev_cycle->m_members [quorumIndex].end ());
691+ }
692+ quorumMembers.insert (quorumMembers.end (),
693+ newQuarterMembers[quorumIndex].begin (),
694+ newQuarterMembers[quorumIndex].end ());
695+
696+ return quorumMembers;
697+ }
698+
600699QuorumMembers GetAllQuorumMembers (Consensus::LLMQType llmqType, const UtilParameters& util_params, bool reset_cache)
601700{
602701 static RecursiveMutex cs_members;
0 commit comments