@@ -56,24 +56,51 @@ pub const MINIMUM_SLOTS_PER_EPOCH: u64 = 32;
5656#[ derive( Debug , CloneZeroed , PartialEq , Eq ) ]
5757pub struct EpochSchedule {
5858 /// The maximum number of slots in each epoch.
59- slots_per_epoch : [ u8 ; 8 ] ,
59+ pub slots_per_epoch : u64 ,
6060
6161 /// A number of slots before beginning of an epoch to calculate
6262 /// a leader schedule for that epoch.
63- leader_schedule_slot_offset : [ u8 ; 8 ] ,
63+ pub leader_schedule_slot_offset : u64 ,
6464
6565 /// Whether epochs start short and grow.
66- pub warmup : u8 ,
66+ pub warmup : bool ,
6767
6868 /// The first epoch after the warmup period.
6969 ///
7070 /// Basically: `log2(slots_per_epoch) - log2(MINIMUM_SLOTS_PER_EPOCH)`.
71- first_normal_epoch : [ u8 ; 8 ] ,
71+ pub first_normal_epoch : u64 ,
7272
7373 /// The first slot after the warmup period.
7474 ///
7575 /// Basically: `MINIMUM_SLOTS_PER_EPOCH * (2.pow(first_normal_epoch) - 1)`.
76- first_normal_slot : [ u8 ; 8 ] ,
76+ pub first_normal_slot : u64 ,
77+ }
78+
79+ /// Pod (Plain Old Data) representation of [`EpochSchedule`] with no padding.
80+ ///
81+ /// This type can be safely loaded via `sol_get_sysvar` without undefined behavior.
82+ #[ repr( C ) ]
83+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
84+ pub struct PodEpochSchedule {
85+ pub slots_per_epoch : [ u8 ; 8 ] ,
86+ pub leader_schedule_slot_offset : [ u8 ; 8 ] ,
87+ pub warmup : u8 ,
88+ pub first_normal_epoch : [ u8 ; 8 ] ,
89+ pub first_normal_slot : [ u8 ; 8 ] ,
90+ }
91+
92+ const _: ( ) = assert ! ( core:: mem:: size_of:: <PodEpochSchedule >( ) == 33 ) ;
93+
94+ impl From < PodEpochSchedule > for EpochSchedule {
95+ fn from ( pod : PodEpochSchedule ) -> Self {
96+ Self {
97+ slots_per_epoch : u64:: from_le_bytes ( pod. slots_per_epoch ) ,
98+ leader_schedule_slot_offset : u64:: from_le_bytes ( pod. leader_schedule_slot_offset ) ,
99+ warmup : pod. warmup != 0 ,
100+ first_normal_epoch : u64:: from_le_bytes ( pod. first_normal_epoch ) ,
101+ first_normal_slot : u64:: from_le_bytes ( pod. first_normal_slot ) ,
102+ }
103+ }
77104}
78105
79106impl Default for EpochSchedule {
@@ -87,40 +114,18 @@ impl Default for EpochSchedule {
87114}
88115
89116impl EpochSchedule {
90- pub fn slots_per_epoch ( & self ) -> u64 {
91- u64:: from_le_bytes ( self . slots_per_epoch )
92- }
93-
94- pub fn leader_schedule_slot_offset ( & self ) -> u64 {
95- u64:: from_le_bytes ( self . leader_schedule_slot_offset )
96- }
97-
98- pub fn warmup ( & self ) -> bool {
99- match self . warmup {
100- 0 => false ,
101- 1 => true ,
102- _ => panic ! ( "invalid warmup value" ) ,
103- }
104- }
105-
106- pub fn first_normal_epoch ( & self ) -> u64 {
107- u64:: from_le_bytes ( self . first_normal_epoch )
108- }
109-
110- pub fn first_normal_slot ( & self ) -> u64 {
111- u64:: from_le_bytes ( self . first_normal_slot )
112- }
113-
114117 pub fn new ( slots_per_epoch : u64 ) -> Self {
115118 Self :: custom ( slots_per_epoch, slots_per_epoch, true )
116119 }
120+
117121 pub fn without_warmup ( ) -> Self {
118122 Self :: custom (
119123 DEFAULT_SLOTS_PER_EPOCH ,
120124 DEFAULT_LEADER_SCHEDULE_SLOT_OFFSET ,
121125 false ,
122126 )
123127 }
128+
124129 pub fn custom ( slots_per_epoch : u64 , leader_schedule_slot_offset : u64 , warmup : bool ) -> Self {
125130 assert ! ( slots_per_epoch >= MINIMUM_SLOTS_PER_EPOCH ) ;
126131 let ( first_normal_epoch, first_normal_slot) = if warmup {
@@ -137,40 +142,40 @@ impl EpochSchedule {
137142 ( 0 , 0 )
138143 } ;
139144 EpochSchedule {
140- slots_per_epoch : slots_per_epoch . to_le_bytes ( ) ,
141- leader_schedule_slot_offset : leader_schedule_slot_offset . to_le_bytes ( ) ,
142- warmup : warmup as u8 ,
143- first_normal_epoch : first_normal_epoch . to_le_bytes ( ) ,
144- first_normal_slot : first_normal_slot . to_le_bytes ( ) ,
145+ slots_per_epoch,
146+ leader_schedule_slot_offset,
147+ warmup,
148+ first_normal_epoch,
149+ first_normal_slot,
145150 }
146151 }
147152
148153 /// get the length of the given epoch (in slots)
149154 pub fn get_slots_in_epoch ( & self , epoch : u64 ) -> u64 {
150- if epoch < self . first_normal_epoch ( ) {
155+ if epoch < self . first_normal_epoch {
151156 2u64 . saturating_pow (
152157 ( epoch as u32 ) . saturating_add ( MINIMUM_SLOTS_PER_EPOCH . trailing_zeros ( ) ) ,
153158 )
154159 } else {
155- self . slots_per_epoch ( )
160+ self . slots_per_epoch
156161 }
157162 }
158163
159164 /// get the epoch for which the given slot should save off
160165 /// information about stakers
161166 pub fn get_leader_schedule_epoch ( & self , slot : u64 ) -> u64 {
162- if slot < self . first_normal_slot ( ) {
167+ if slot < self . first_normal_slot {
163168 // until we get to normal slots, behave as if leader_schedule_slot_offset == slots_per_epoch
164169 self . get_epoch_and_slot_index ( slot) . 0 . saturating_add ( 1 )
165170 } else {
166- let new_slots_since_first_normal_slot = slot. saturating_sub ( self . first_normal_slot ( ) ) ;
167- let new_first_normal_leader_schedule_slot = new_slots_since_first_normal_slot
168- . saturating_add ( self . leader_schedule_slot_offset ( ) ) ;
171+ let new_slots_since_first_normal_slot = slot. saturating_sub ( self . first_normal_slot ) ;
172+ let new_first_normal_leader_schedule_slot =
173+ new_slots_since_first_normal_slot . saturating_add ( self . leader_schedule_slot_offset ) ;
169174 let new_epochs_since_first_normal_leader_schedule =
170175 new_first_normal_leader_schedule_slot
171- . checked_div ( self . slots_per_epoch ( ) )
176+ . checked_div ( self . slots_per_epoch )
172177 . unwrap_or ( 0 ) ;
173- self . first_normal_epoch ( )
178+ self . first_normal_epoch
174179 . saturating_add ( new_epochs_since_first_normal_leader_schedule)
175180 }
176181 }
@@ -182,7 +187,7 @@ impl EpochSchedule {
182187
183188 /// get epoch and offset into the epoch for the given slot
184189 pub fn get_epoch_and_slot_index ( & self , slot : u64 ) -> ( u64 , u64 ) {
185- if slot < self . first_normal_slot ( ) {
190+ if slot < self . first_normal_slot {
186191 let epoch = slot
187192 . saturating_add ( MINIMUM_SLOTS_PER_EPOCH )
188193 . saturating_add ( 1 )
@@ -199,28 +204,28 @@ impl EpochSchedule {
199204 slot. saturating_sub ( epoch_len. saturating_sub ( MINIMUM_SLOTS_PER_EPOCH ) ) ,
200205 )
201206 } else {
202- let normal_slot_index = slot. saturating_sub ( self . first_normal_slot ( ) ) ;
207+ let normal_slot_index = slot. saturating_sub ( self . first_normal_slot ) ;
203208 let normal_epoch_index = normal_slot_index
204- . checked_div ( self . slots_per_epoch ( ) )
209+ . checked_div ( self . slots_per_epoch )
205210 . unwrap_or ( 0 ) ;
206- let epoch = self . first_normal_epoch ( ) . saturating_add ( normal_epoch_index) ;
211+ let epoch = self . first_normal_epoch . saturating_add ( normal_epoch_index) ;
207212 let slot_index = normal_slot_index
208- . checked_rem ( self . slots_per_epoch ( ) )
213+ . checked_rem ( self . slots_per_epoch )
209214 . unwrap_or ( 0 ) ;
210215 ( epoch, slot_index)
211216 }
212217 }
213218
214219 pub fn get_first_slot_in_epoch ( & self , epoch : u64 ) -> u64 {
215- if epoch <= self . first_normal_epoch ( ) {
220+ if epoch <= self . first_normal_epoch {
216221 2u64 . saturating_pow ( epoch as u32 )
217222 . saturating_sub ( 1 )
218223 . saturating_mul ( MINIMUM_SLOTS_PER_EPOCH )
219224 } else {
220225 epoch
221- . saturating_sub ( self . first_normal_epoch ( ) )
222- . saturating_mul ( self . slots_per_epoch ( ) )
223- . saturating_add ( self . first_normal_slot ( ) )
226+ . saturating_sub ( self . first_normal_epoch )
227+ . saturating_mul ( self . slots_per_epoch )
228+ . saturating_add ( self . first_normal_slot )
224229 }
225230 }
226231
@@ -295,8 +300,13 @@ mod tests {
295300
296301 #[ test]
297302 fn test_clone ( ) {
298- let epoch_schedule =
299- EpochSchedule :: custom ( MINIMUM_SLOTS_PER_EPOCH , MINIMUM_SLOTS_PER_EPOCH , true ) ;
303+ let epoch_schedule = EpochSchedule {
304+ slots_per_epoch : 1 ,
305+ leader_schedule_slot_offset : 2 ,
306+ warmup : true ,
307+ first_normal_epoch : 4 ,
308+ first_normal_slot : 5 ,
309+ } ;
300310 #[ allow( clippy:: clone_on_copy) ]
301311 let cloned_epoch_schedule = epoch_schedule. clone ( ) ;
302312 assert_eq ! ( cloned_epoch_schedule, epoch_schedule) ;
0 commit comments