@@ -68,9 +68,12 @@ impl GlobalStateEvaluator {
68
68
}
69
69
70
70
/// Determine what the active signer protocol version should be
71
- ///
72
- /// NOTE: do not call this function unless the evaluator has already been updated with the current local state
73
- pub fn determine_active_signer_protocol_version ( & self ) -> Option < u64 > {
71
+ fn determine_active_signer_protocol_version (
72
+ & mut self ,
73
+ local_address : StacksAddress ,
74
+ local_update : StateMachineUpdateMessage ,
75
+ ) -> Option < u64 > {
76
+ self . insert_update ( local_address. clone ( ) , local_update) ;
74
77
let mut protocol_versions = HashMap :: new ( ) ;
75
78
for ( address, update) in & self . address_updates {
76
79
let Some ( weight) = self . address_weights . get ( address) else {
@@ -80,17 +83,27 @@ impl GlobalStateEvaluator {
80
83
. entry ( update. local_supported_signer_protocol_version )
81
84
. or_insert_with ( || 0 ) ;
82
85
* entry += weight;
83
- if * entry >= self . total_weight * 7 / 10 {
84
- return Some ( update. local_supported_signer_protocol_version ) ;
86
+ }
87
+ // find the highest version number supported by a threshold number of signers
88
+ let mut protocol_versions: Vec < _ > = protocol_versions. into_iter ( ) . collect ( ) ;
89
+ protocol_versions. sort_by_key ( |( version, _) | * version) ;
90
+ let mut total_weight_support = 0 ;
91
+ for ( version, weight_support) in protocol_versions. into_iter ( ) . rev ( ) {
92
+ total_weight_support += weight_support;
93
+ if total_weight_support >= self . total_weight * 7 / 10 {
94
+ return Some ( version) ;
85
95
}
86
96
}
87
- None
97
+ return None ;
88
98
}
89
99
90
100
/// Determine what the global burn view is if there is one
91
- ///
92
- /// NOTE: do not call this function unless the evaluator has already been updated with the current local state
93
- pub fn determine_global_burn_view ( & self ) -> Option < ( ConsensusHash , u64 ) > {
101
+ pub fn determine_global_burn_view (
102
+ & mut self ,
103
+ local_address : StacksAddress ,
104
+ local_update : StateMachineUpdateMessage ,
105
+ ) -> Option < ( ConsensusHash , u64 ) > {
106
+ self . insert_update ( local_address. clone ( ) , local_update) ;
94
107
let mut burn_blocks = HashMap :: new ( ) ;
95
108
for ( address, update) in & self . address_updates {
96
109
let Some ( weight) = self . address_weights . get ( address) else {
@@ -112,10 +125,13 @@ impl GlobalStateEvaluator {
112
125
}
113
126
114
127
/// Check if there is an agreed upon global current miner viewpoint
115
- ///
116
- /// NOTE: do not call this function unless the evaluator has already been updated with the current local state
117
- pub fn determine_global_state ( & self ) -> Option < SignerStateMachine > {
118
- let active_signer_protocol_version = self . determine_active_signer_protocol_version ( ) ?;
128
+ pub fn determine_global_state (
129
+ & mut self ,
130
+ local_address : StacksAddress ,
131
+ local_update : StateMachineUpdateMessage ,
132
+ ) -> Option < SignerStateMachine > {
133
+ let active_signer_protocol_version =
134
+ self . determine_active_signer_protocol_version ( local_address, local_update) ?;
119
135
let mut state_views = HashMap :: new ( ) ;
120
136
for ( address, update) in & self . address_updates {
121
137
let Some ( weight) = self . address_weights . get ( address) else {
@@ -145,10 +161,13 @@ impl GlobalStateEvaluator {
145
161
}
146
162
147
163
/// Check if there is an agreed upon global current miner viewpoint
148
- ///
149
- /// NOTE: do not call this function unless the evaluator has already been updated with the current local state
150
- pub fn determine_global_current_miner ( & self ) -> Option < StateMachineUpdateMinerState > {
151
- let ( global_burn_block, _) = self . determine_global_burn_view ( ) ?;
164
+ pub fn determine_global_current_miner (
165
+ & mut self ,
166
+ local_address : StacksAddress ,
167
+ local_update : StateMachineUpdateMessage ,
168
+ ) -> Option < StateMachineUpdateMinerState > {
169
+ let ( global_burn_block, _) =
170
+ self . determine_global_burn_view ( local_address, local_update) ?;
152
171
let mut miner_views = HashMap :: new ( ) ;
153
172
for ( address, update) in & self . address_updates {
154
173
let Some ( weight) = self . address_weights . get ( address) else {
@@ -173,17 +192,20 @@ impl GlobalStateEvaluator {
173
192
None
174
193
}
175
194
176
- /// Determines whether a signer, based on the provided burn block view (`current_burn_block`),
177
- /// should update ( capitulate) its current miner view to a new state. This is not necessarily the same as the current global view
195
+ /// Determines whether a signer with the `local_address` and `local_update` should
196
+ /// should capitulate its current miner view to a new state. This is not necessarily the same as the current global view
178
197
/// of the miner as it is up to signers to capitulate before this becomes the finalized view.
179
- ///
180
- /// NOTE: do not call this function unless the evaluator has already been updated with the current local state
181
198
pub fn capitulate_miner_view (
182
- & self ,
183
- current_burn_block : ConsensusHash ,
199
+ & mut self ,
184
200
signerdb : & mut SignerDb ,
201
+ local_address : StacksAddress ,
202
+ local_update : StateMachineUpdateMessage ,
185
203
) -> Option < StateMachineUpdateMinerState > {
186
- let ( global_burn_view, _) = self . determine_global_burn_view ( ) ?;
204
+ let StateMachineUpdateContent :: V0 {
205
+ burn_block : current_burn_block,
206
+ ..
207
+ } = local_update. content . clone ( ) ;
208
+ let ( global_burn_view, _) = self . determine_global_burn_view ( local_address, local_update) ?;
187
209
if current_burn_block != global_burn_view {
188
210
return None ;
189
211
}
@@ -761,50 +783,66 @@ impl LocalStateMachine {
761
783
eval : & mut GlobalStateEvaluator ,
762
784
local_address : StacksAddress ,
763
785
) {
764
- // Before we ever access eval...we should update with our own viewpoint
786
+ // Before we ever access eval...we should make sure to include our own local state machine update message in the evaluation
765
787
let local_update: Result < StateMachineUpdateMessage , _ > = ( & * self ) . try_into ( ) ;
766
- let Ok ( local_update) = local_update else {
788
+ let Ok ( mut local_update) = local_update else {
767
789
return ;
768
790
} ;
791
+
769
792
let old_protocol_version = local_update. active_signer_protocol_version ;
793
+ // First check if we should update our active protocol version
794
+ let active_signer_protocol_version = eval
795
+ . determine_active_signer_protocol_version ( local_address, local_update. clone ( ) )
796
+ . unwrap_or ( old_protocol_version) ;
797
+
770
798
let StateMachineUpdateContent :: V0 {
771
799
burn_block,
772
800
burn_block_height,
773
801
current_miner,
774
802
..
775
- } = & local_update. content . clone ( ) ;
803
+ } = & local_update. content ;
776
804
777
- eval. insert_update ( local_address, local_update) ;
805
+ if active_signer_protocol_version != old_protocol_version {
806
+ info ! ( "Updating active signer protocol version from {old_protocol_version} to {active_signer_protocol_version}" ) ;
807
+ * self = Self :: Initialized ( SignerStateMachine {
808
+ burn_block : * burn_block,
809
+ burn_block_height : * burn_block_height,
810
+ current_miner : current_miner. into ( ) ,
811
+ active_signer_protocol_version,
812
+ } ) ;
813
+ // Because we updated our active signer protocol version, update local_update so its included in the subsequent evaluations
814
+ let update: Result < StateMachineUpdateMessage , _ > = ( & * self ) . try_into ( ) ;
815
+ let Ok ( update) = update else {
816
+ return ;
817
+ } ;
818
+ local_update = update;
819
+ }
778
820
779
- let active_signer_protocol_version = eval
780
- . determine_active_signer_protocol_version ( )
781
- . unwrap_or ( old_protocol_version ) ;
782
- let Some ( new_miner ) = eval . capitulate_miner_view ( * burn_block , signerdb ) else {
821
+ // Check if we should also capitulate our miner viewpoint
822
+ let Some ( new_miner ) =
823
+ eval . capitulate_miner_view ( signerdb , local_address , local_update . clone ( ) )
824
+ else {
783
825
return ;
784
826
} ;
785
827
786
- if current_miner != & new_miner {
787
- if active_signer_protocol_version != old_protocol_version {
788
- info ! ( "Updating active signer protocol version from {old_protocol_version} to {active_signer_protocol_version}" ) ;
789
- }
828
+ let StateMachineUpdateContent :: V0 {
829
+ burn_block,
830
+ burn_block_height,
831
+ current_miner,
832
+ ..
833
+ } = local_update. content ;
834
+
835
+ if current_miner != new_miner {
790
836
info ! ( "Capitulating local state machine's current miner viewpoint" ;
791
837
"current_miner" => ?current_miner,
792
838
"new_miner" => ?new_miner,
793
839
) ;
794
840
* self = Self :: Initialized ( SignerStateMachine {
795
- burn_block : * burn_block ,
796
- burn_block_height : * burn_block_height ,
841
+ burn_block,
842
+ burn_block_height,
797
843
current_miner : ( & new_miner) . into ( ) ,
798
844
active_signer_protocol_version,
799
845
} ) ;
800
- } else if active_signer_protocol_version != old_protocol_version {
801
- info ! ( "Updating active signer protocol version from {old_protocol_version} to {active_signer_protocol_version}" ) ;
802
- * self = Self :: Initialized ( SignerStateMachine {
803
- burn_block : * burn_block,
804
- burn_block_height : * burn_block_height,
805
- current_miner : current_miner. into ( ) ,
806
- active_signer_protocol_version,
807
- } ) ;
808
846
}
809
847
}
810
848
}
0 commit comments