PR #934 fixed the per-quorum ChainLock signature keying on the feed_qr_info rotation path, but the older collapsing behaviour survives in MasternodeList::apply_diff.
What remains
dash/src/sml/masternode_list/apply_diff.rs still takes rotating_sig from the first rotating quorum it encounters in a diff:
let mut rotating_sig = None;
...
if rotating_sig.is_none()
&& let Some(sig) = quorum_sig_lookup.get(idx).copied().flatten()
{
rotating_sig = Some(*sig);
}
feed_qr_info assembles that value into the [s2, s1, s0] triple it passes to apply_diff for mn_list_diff_tip, so rotated quorums landing in masternode_lists[tip].quorums still carry a signature prefix taken from another quorum's cycle. This is the same class of defect #907 was caused by, just on a different path.
Core keys each rotated quorum's ChainLock signature to that quorum's own work block (CSimplifiedMNListDiff::BuildQuorumChainlockInfo, src/evo/smldiff.cpp:88-93), which is what PR #934's rotation_cl_sigs_by_work_height now implements for the QRInfo path.
Why it is currently dormant
Tip-list validation excludes rotating quorum types, and known_qualified_quorum_entry reads only from rotated_quorums_per_cycle, so no stale tuple leaks back into the authoritative map and no wedge results today. The risk is latent: any future code path that validates rotated quorums off the tip masternode list, or that trusts verifying_chain_lock_signature on those entries, inherits the wrong signatures and records spurious Invalid statuses.
Suggested fix
Reuse the per-work-height map PR #934 introduced rather than reconstructing the collapse. MasternodeListEngine::rotation_cl_sigs_by_work_height plus quarter_sigs_for_quorum already produce the correct per-quorum tuple, so apply_diff should either receive the resolved per-quorum signatures or stop attaching rotation signatures on this path entirely and leave them to the QRInfo path that keys them correctly.
PR #934 fixed the per-quorum ChainLock signature keying on the
feed_qr_inforotation path, but the older collapsing behaviour survives inMasternodeList::apply_diff.What remains
dash/src/sml/masternode_list/apply_diff.rsstill takesrotating_sigfrom the first rotating quorum it encounters in a diff:feed_qr_infoassembles that value into the[s2, s1, s0]triple it passes toapply_diffformn_list_diff_tip, so rotated quorums landing inmasternode_lists[tip].quorumsstill carry a signature prefix taken from another quorum's cycle. This is the same class of defect #907 was caused by, just on a different path.Core keys each rotated quorum's ChainLock signature to that quorum's own work block (
CSimplifiedMNListDiff::BuildQuorumChainlockInfo,src/evo/smldiff.cpp:88-93), which is what PR #934'srotation_cl_sigs_by_work_heightnow implements for the QRInfo path.Why it is currently dormant
Tip-list validation excludes rotating quorum types, and
known_qualified_quorum_entryreads only fromrotated_quorums_per_cycle, so no stale tuple leaks back into the authoritative map and no wedge results today. The risk is latent: any future code path that validates rotated quorums off the tip masternode list, or that trustsverifying_chain_lock_signatureon those entries, inherits the wrong signatures and records spuriousInvalidstatuses.Suggested fix
Reuse the per-work-height map PR #934 introduced rather than reconstructing the collapse.
MasternodeListEngine::rotation_cl_sigs_by_work_heightplusquarter_sigs_for_quorumalready produce the correct per-quorum tuple, soapply_diffshould either receive the resolved per-quorum signatures or stop attaching rotation signatures on this path entirely and leave them to the QRInfo path that keys them correctly.