1+ use std:: collections:: BTreeMap ;
2+ use crate :: sml:: llmq_type:: { LLMQParams , LLMQType } ;
3+ use crate :: sml:: llmq_type:: rotation:: LLMQQuarterReconstructionType ;
4+ use crate :: sml:: masternode_list:: MasternodeList ;
5+ use crate :: sml:: masternode_list_entry:: MasternodeListEntry ;
6+ use crate :: sml:: quorum_validation_error:: QuorumValidationError ;
7+
8+ impl MasternodeList {
9+ fn quorum_quarter_members_by_reconstruction_type (
10+ & self ,
11+ reconstruction_type : LLMQQuarterReconstructionType ,
12+ llmq_params : & LLMQParams ,
13+ work_block_height : u32 ,
14+ ) -> Result < Vec < Vec < MasternodeListEntry > > , QuorumValidationError > {
15+ let work_block_hash = self . provider . lookup_block_hash_by_height ( work_block_height) ;
16+ if work_block_hash. is_zero ( ) {
17+ warn ! ( "quorum_quarter_members_by_reconstruction_type: empty work block hash for {work_block_height}" )
18+ }
19+ let masternode_list = self . masternode_list_for_block_hash ( work_block_hash)
20+ . ok_or ( QuorumValidationError :: RequiredMasternodeListNotPresent ( work_block_hash) ) ?;
21+ let llmq_type = llmq_params. r#type . clone ( ) ;
22+ let quorum_count = llmq_params. signing_active_quorum_count as usize ;
23+ let quorum_size = llmq_params. size as usize ;
24+ let quarter_size = quorum_size / 4 ;
25+ let quorum_modifier_type = self . llmq_modifier_type_for ( llmq_type, work_block_hash, work_block_height) ;
26+ let quorum_modifier = quorum_modifier_type. build_llmq_hash ( ) ;
27+ match reconstruction_type {
28+ LLMQQuarterReconstructionType :: New { previous_quarters, skip_removed_masternodes } => {
29+ let ( used_at_h_masternodes, unused_at_h_masternodes, used_at_h_indexed_masternodes) =
30+ masternode_list. usage_info ( previous_quarters, skip_removed_masternodes, quorum_count) ;
31+ Ok ( apply_skip_strategy_of_type ( LLMQQuarterUsageType :: New ( used_at_h_indexed_masternodes) , used_at_h_masternodes, unused_at_h_masternodes, work_block_height, quorum_modifier, quorum_count, quarter_size) )
32+ } ,
33+ LLMQQuarterReconstructionType :: Snapshot => {
34+ if let Some ( snapshot) = self . cache . maybe_snapshot ( work_block_hash) {
35+ let ( used_at_h_masternodes, unused_at_h_masternodes) =
36+ usage_info_from_snapshot ( & masternode_list. masternodes , & snapshot, quorum_modifier, work_block_height) ;
37+ Ok ( apply_skip_strategy_of_type ( LLMQQuarterUsageType :: Snapshot ( snapshot) , used_at_h_masternodes, unused_at_h_masternodes, work_block_height, quorum_modifier, quorum_count, quarter_size) )
38+ } else {
39+ Err ( CoreProviderError :: NoSnapshot )
40+ }
41+
42+ // self.provider.find_snapshot(work_block_hash, &self.cache)
43+ // .map(|snapshot| {
44+ // let (used_at_h_masternodes, unused_at_h_masternodes) =
45+ // usage_info_from_snapshot(masternode_list, &snapshot, quorum_modifier, work_block_height);
46+ // apply_skip_strategy_of_type(LLMQQuarterUsageType::Snapshot(snapshot), used_at_h_masternodes, unused_at_h_masternodes, work_block_height, quorum_modifier, quorum_count, quarter_size)
47+ // })
48+ }
49+ }
50+ }
51+
52+
53+ fn rotate_members (
54+ & self ,
55+ cycle_base_height : u32 ,
56+ llmq_params : LLMQParams ,
57+ skip_removed_masternodes : bool ,
58+ // cache: &Arc<RwLock<MasternodeProcessorCache>>
59+ // cached_mn_lists: &BTreeMap<UInt256, MasternodeList>,
60+ // cached_llmq_snapshots: &BTreeMap<UInt256, LLMQSnapshot>,
61+ // cached_cl_signatures: &BTreeMap<UInt256, UInt768>,
62+ // unknown_mn_lists: &mut Vec<UInt256>,
63+ ) -> Result < Vec < Vec < MasternodeListEntry > > , QuorumValidationError > {
64+ let num_quorums = llmq_params. signing_active_quorum_count as usize ;
65+ let cycle_length = llmq_params. dkg_params . interval ;
66+ let work_block_height_for_index = |index : u32 | ( cycle_base_height - index * cycle_length) - 8 ;
67+ // Reconstruct quorum members at h - 3c from snapshot
68+ let q_h_m_3c = self . quorum_quarter_members_by_reconstruction_type ( LLMQQuarterReconstructionType :: Snapshot , & llmq_params, work_block_height_for_index ( 3 ) ) ?;
69+ // Reconstruct quorum members at h - 2c from snapshot
70+ let q_h_m_2c = self . quorum_quarter_members_by_reconstruction_type ( LLMQQuarterReconstructionType :: Snapshot , & llmq_params, work_block_height_for_index ( 2 ) ) ?;
71+ // Reconstruct quorum members at h - c from snapshot
72+ let q_h_m_c = self . quorum_quarter_members_by_reconstruction_type ( LLMQQuarterReconstructionType :: Snapshot , & llmq_params, work_block_height_for_index ( 1 ) ) ?;
73+ // Determine quorum members at new index
74+ let reconstruction_type = LLMQQuarterReconstructionType :: New { previous_quarters : [ & q_h_m_c, & q_h_m_2c, & q_h_m_3c] , skip_removed_masternodes } ;
75+ let quarter_new = self . quorum_quarter_members_by_reconstruction_type ( reconstruction_type, & llmq_params, work_block_height_for_index ( 0 ) ) ?;
76+ let mut quorum_members =
77+ Vec :: < Vec < MasternodeListEntry > > :: with_capacity ( num_quorums) ;
78+ ( 0 ..num_quorums) . for_each ( |index| {
79+ add_quorum_members_from_quarter ( & mut quorum_members, & q_h_m_3c, index) ;
80+ add_quorum_members_from_quarter ( & mut quorum_members, & q_h_m_2c, index) ;
81+ add_quorum_members_from_quarter ( & mut quorum_members, & q_h_m_c, index) ;
82+ add_quorum_members_from_quarter ( & mut quorum_members, & quarter_new, index) ;
83+ } ) ;
84+ Ok ( quorum_members)
85+ }
86+
87+ /// Determine masternodes which is responsible for signing at this quorum index
88+ #[ allow( clippy:: too_many_arguments) ]
89+ pub fn get_rotated_masternodes_for_quorum (
90+ & self ,
91+ llmq_type : LLMQType ,
92+ block_hash : [ u8 ; 32 ] ,
93+ block_height : u32 ,
94+ skip_removed_masternodes : bool ,
95+ ) -> Result < Vec < MasternodeListEntry > , CoreProviderError > {
96+ let mut llmq_members_lock = self . cache . llmq_members . write ( ) . unwrap ( ) ;
97+ let cached_members_of_llmq_type_opt = llmq_members_lock. get_mut ( & llmq_type) ;
98+ if cached_members_of_llmq_type_opt. is_some ( ) {
99+ if let Some ( cached_members) = cached_members_of_llmq_type_opt. as_ref ( ) . unwrap ( ) . get ( & block_hash) . cloned ( ) {
100+ drop ( llmq_members_lock) ;
101+ return Ok ( cached_members) ;
102+ }
103+ } else {
104+ llmq_members_lock. insert ( llmq_type. clone ( ) , BTreeMap :: new ( ) ) ;
105+ }
106+
107+ let cached_members_of_llmq_type = llmq_members_lock. get_mut ( & llmq_type) . unwrap ( ) ;
108+ let llmq_params = llmq_type. params ( ) ;
109+ let quorum_index = block_height % llmq_params. dkg_params . interval ;
110+ let cycle_base_height = block_height - quorum_index;
111+ let cycle_base_hash = self . provider . lookup_block_hash_by_height ( cycle_base_height) ;
112+ let mut llmq_indexed_members_lock = self . cache . llmq_indexed_members . write ( ) . unwrap ( ) ;
113+ if let Some ( map_by_type_indexed) = llmq_indexed_members_lock. get ( & llmq_type) {
114+ let indexed_hash = LLMQIndexedHash :: from ( ( cycle_base_hash, quorum_index) ) ;
115+ if let Some ( cached_members) = map_by_type_indexed. get ( & indexed_hash) . cloned ( ) {
116+ cached_members_of_llmq_type. insert ( block_hash, cached_members. clone ( ) ) ;
117+ drop ( llmq_members_lock) ;
118+ drop ( llmq_indexed_members_lock) ;
119+ return Ok ( cached_members) ;
120+ }
121+ } else {
122+ llmq_indexed_members_lock. insert ( llmq_type. clone ( ) , BTreeMap :: new ( ) ) ;
123+ }
124+ drop ( llmq_indexed_members_lock) ;
125+ let rotated_members = self . rotate_members ( cycle_base_height, llmq_params, skip_removed_masternodes) ?;
126+ let result = if let Some ( rotated_members_at_index) = rotated_members. get ( quorum_index as usize ) {
127+ cached_members_of_llmq_type. insert ( block_hash, rotated_members_at_index. clone ( ) ) ;
128+ Ok ( rotated_members_at_index. clone ( ) )
129+ } else {
130+ Err ( CoreProviderError :: NullResult ( format ! ( "No rotated_members for llmq index {} ({})" , quorum_index, block_hash. to_hex( ) ) ) )
131+ } ;
132+ drop ( llmq_members_lock) ;
133+
134+ self . cache . write_llmq_indexed_members ( |lock| {
135+ lock. get_mut ( & llmq_type)
136+ . unwrap ( )
137+ . extend ( rotated_members. into_iter ( )
138+ . enumerate ( )
139+ . map ( |( index, members) |
140+ ( LLMQIndexedHash :: from ( ( cycle_base_hash, index) ) , members) ) ) ;
141+ } ) ;
142+ result
143+ }
144+ }
0 commit comments