1- use std:: cmp:: { max, min} ;
2-
31use blake2:: { Blake2b512 , Digest } ;
42use serde:: Deserialize ;
53
6- const SLOTS_PER_EPOCH : u32 = 7140 ;
7- const GRACE_PERIOD_END : u32 = 1440 ;
8- const SLOTS_PER_SUB_WINDOW : u32 = 7 ;
9- const SUB_WINDOWS_PER_WINDOW : u32 = 11 ;
10- // FIXME: retrieve this through archive node
11- const SUB_WINDOW_DENSITIES : [ u32 ; 11 ] = [ 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 ] ;
12-
134#[ derive( Clone ) ]
145pub struct ConsensusState {
15- pub slot_since_genesis : u32 ,
16- pub epoch_count : u32 ,
17- pub staking_epoch_data : EpochData ,
18- pub next_epoch_data : EpochData ,
19- pub min_window_density : u32 ,
206 pub block_height : u32 ,
217 pub last_vrf_output : String ,
228}
239
24- #[ derive( Debug , Clone , Deserialize ) ]
25- #[ serde( rename_all = "camelCase" ) ]
26- pub struct EpochData {
27- pub lock_checkpoint : String ,
28- }
29-
3010#[ derive( Clone , Deserialize ) ]
3111#[ serde( rename_all = "camelCase" ) ]
3212pub struct ConsensusStateQuery {
33- pub slot_since_genesis : String ,
34- pub epoch_count : String ,
35- pub staking_epoch_data : EpochData ,
36- pub next_epoch_data : EpochData ,
37- pub min_window_density : String ,
3813 pub block_height : String ,
3914 pub last_vrf_output : String ,
4015}
4116
4217impl From < ConsensusStateQuery > for ConsensusState {
4318 fn from ( value : ConsensusStateQuery ) -> Self {
4419 Self {
45- slot_since_genesis : u32:: from_str_radix ( & value. slot_since_genesis , 10 ) . unwrap ( ) ,
46- epoch_count : u32:: from_str_radix ( & value. epoch_count , 10 ) . unwrap ( ) ,
47- staking_epoch_data : value. staking_epoch_data ,
48- next_epoch_data : value. next_epoch_data ,
49- min_window_density : u32:: from_str_radix ( & value. min_window_density , 10 ) . unwrap ( ) ,
5020 block_height : u32:: from_str_radix ( & value. block_height , 10 ) . unwrap ( ) ,
5121 last_vrf_output : value. last_vrf_output ,
5222 }
@@ -68,99 +38,14 @@ impl ConsensusState {
6838 . ok_or ( "Could not parse consensus state: JSON structure is unexpected" ) ?
6939 . to_owned ( ) ;
7040
71- dbg ! ( consensus_state_query_value. to_owned( ) ) ;
72-
7341 let consensus_state_query: ConsensusStateQuery =
7442 serde_json:: from_value ( consensus_state_query_value)
7543 . map_err ( |err| format ! ( "Could not parse mina consensus state: {err}" ) ) ?;
7644
7745 Ok ( consensus_state_query. into ( ) )
7846 }
7947
80- pub fn select_secure_chain ( & self , other : & Self ) -> Self {
81- if self . is_short_range ( other) {
82- self . select_longer_chain ( other)
83- } else {
84- let tip_density = self . relative_min_window_density ( other) ;
85- let candidate_density = other. relative_min_window_density ( self ) ;
86- if candidate_density > tip_density {
87- other. clone ( )
88- } else if candidate_density == tip_density {
89- self . select_longer_chain ( other)
90- } else {
91- self . clone ( )
92- }
93- }
94- }
95-
96- fn is_short_range ( & self , other : & Self ) -> bool {
97- if self . epoch_count == other. epoch_count {
98- // Simple case: blocks have same previous epoch, so compare previous epochs' lock_checkpoints
99- self . staking_epoch_data . lock_checkpoint == other. staking_epoch_data . lock_checkpoint
100- } else {
101- // Check for previous epoch case using both orientations
102- self . check ( other) || other. check ( self )
103- }
104- }
105-
106- fn check ( & self , other : & Self ) -> bool {
107- if self . epoch_count == other. epoch_count + 1
108- && other. epoch_slot ( ) >= 2 / 3 * SLOTS_PER_EPOCH
109- {
110- // S1 is one epoch ahead of S2 and S2 is not in the seed update range
111- self . staking_epoch_data . lock_checkpoint == other. next_epoch_data . lock_checkpoint
112- } else {
113- false
114- }
115- }
116-
117- fn epoch_slot ( & self ) -> u32 {
118- self . slot_since_genesis % SLOTS_PER_EPOCH
119- }
120-
121- fn relative_min_window_density ( & self , other : & Self ) -> u32 {
122- let max_slot = max ( self . slot_since_genesis , other. slot_since_genesis ) ;
123-
124- // Grace-period rule
125- if max_slot < GRACE_PERIOD_END {
126- return self . min_window_density ;
127- }
128-
129- // Compute B1's window projected to max_slot
130- let projected_window = {
131- // Compute shift count
132- let mut shift_count = min (
133- max ( max_slot - self . slot_since_genesis - 1 , 0 ) ,
134- SUB_WINDOWS_PER_WINDOW ,
135- ) ;
136-
137- // Initialize projected window
138- // FIXME: retrieve this through archive node
139- let mut projected_window = SUB_WINDOW_DENSITIES ;
140-
141- // Ring-shift
142- let mut i = self . relative_sub_window ( ) as usize ;
143- while shift_count > 0 {
144- i = ( i + 1 ) % SUB_WINDOWS_PER_WINDOW as usize ;
145- projected_window[ i] = 0 ;
146- shift_count -= 1 ;
147- }
148-
149- projected_window
150- } ;
151-
152- // Compute projected window density
153- let projected_window_density = projected_window. iter ( ) . fold ( 0 , |acc, w| acc + w) ;
154-
155- // Compute minimum window density
156- return min ( self . min_window_density , projected_window_density) ;
157- }
158-
159- fn relative_sub_window ( & self ) -> u32 {
160- ( self . slot_since_genesis / SLOTS_PER_SUB_WINDOW ) % SUB_WINDOWS_PER_WINDOW
161- }
162-
163- fn select_longer_chain ( & self , other : & Self ) -> Self {
48+ pub fn select_longer_chain ( & self , other : & Self ) -> Self {
16449 if self . block_height < other. block_height {
16550 return other. clone ( ) ;
16651 }
@@ -199,12 +84,11 @@ impl ConsensusState {
19984mod tests {
20085 use super :: ConsensusState ;
20186
202- const MINA_CONSENSUS_STATE_QUERY : & str = include_str ! (
203- "../../../../../batcher/aligned/test_files/mina/mina_devnet_protocol_query.json"
204- ) ;
87+ const MINA_CONSENSUS_STATE_QUERY : & str =
88+ include_str ! ( "../../../../batcher/aligned/test_files/mina/mina_devnet_protocol_query.json" ) ;
20589
20690 #[ test]
207- fn test_parse_consensus_state ( ) {
91+ fn parsing_consensus_state_works ( ) {
20892 ConsensusState :: from_json ( MINA_CONSENSUS_STATE_QUERY ) . unwrap ( ) ;
20993 }
21094}
0 commit comments