@@ -3,15 +3,11 @@ use serde::{Deserialize, Serialize};
33use ssz_derive:: { Decode , Encode } ;
44use ssz_types:: {
55 BitList , VariableList ,
6- typenum:: { U262144 , U1073741824 , Unsigned } ,
6+ typenum:: { U262144 , U1073741824 } ,
77} ;
88use tree_hash_derive:: TreeHash ;
99
10- use crate :: {
11- config:: Config ,
12- MAX_HISTORICAL_BLOCK_HASHES ,
13- VALIDATOR_REGISTRY_LIMIT ,
14- } ;
10+ use crate :: { VALIDATOR_REGISTRY_LIMIT , config:: Config } ;
1511
1612#[ derive( Debug , Eq , PartialEq , Clone , Serialize , Deserialize , Encode , Decode , TreeHash ) ]
1713pub struct LeanState {
@@ -34,31 +30,66 @@ pub struct LeanState {
3430}
3531
3632impl LeanState {
37- fn get_justifications_roots_index ( & self , root : & B256 ) -> Option < usize > {
38- self . justifications_roots . iter ( ) . position ( |r| r == root )
39- }
33+ pub fn new ( num_validators : u64 ) -> LeanState {
34+ LeanState {
35+ config : Config { num_validators } ,
4036
41- fn get_justifications_roots_range ( & self , index : & usize ) -> ( usize , usize ) {
42- let start_range = index * MAX_HISTORICAL_BLOCK_HASHES as usize ;
43- let end_range = start_range + VALIDATOR_REGISTRY_LIMIT as usize ;
37+ latest_justified_hash : B256 :: ZERO ,
38+ latest_justified_slot : 0 ,
39+ latest_finalized_hash : B256 :: ZERO ,
40+ latest_finalized_slot : 0 ,
4441
45- ( start_range, end_range)
42+ historical_block_hashes : VariableList :: empty ( ) ,
43+ justified_slots : VariableList :: empty ( ) ,
44+
45+ justifications_roots : VariableList :: empty ( ) ,
46+ justifications_roots_validators : BitList :: with_capacity ( 0 )
47+ . expect ( "Failed to initialize state's justifications_roots_validators" ) ,
48+ }
49+ }
50+
51+ fn get_justifications_roots_index ( & self , root : & B256 ) -> Option < usize > {
52+ self . justifications_roots . iter ( ) . position ( |r| r == root)
4653 }
4754
4855 pub fn initialize_justifications_for_root ( & mut self , root : & B256 ) {
4956 if !self . justifications_roots . contains ( root) {
5057 self . justifications_roots
5158 . push ( * root)
5259 . expect ( "Failed to insert root into justifications_roots" ) ;
60+
61+ let old_length = self . justifications_roots_validators . len ( ) ;
62+ let new_length = old_length + VALIDATOR_REGISTRY_LIMIT as usize ;
63+
64+ let mut new_justifications_roots_validators = BitList :: with_capacity ( new_length)
65+ . expect ( "Failed to initialize new justification bits" ) ;
66+
67+ for ( i, bit) in self . justifications_roots_validators . iter ( ) . enumerate ( ) {
68+ new_justifications_roots_validators
69+ . set ( i, bit)
70+ . expect ( "Failed to initialize justification bits to existing values" ) ;
71+ }
72+
73+ for i in old_length..new_length {
74+ new_justifications_roots_validators
75+ . set ( i, false )
76+ . expect ( "Failed to zero-fill justification bits" ) ;
77+ }
78+
79+ self . justifications_roots_validators = new_justifications_roots_validators;
5380 }
5481 }
5582
5683 pub fn set_justification ( & mut self , root : & B256 , validator_id : & u64 , value : bool ) {
5784 let index = self
5885 . get_justifications_roots_index ( root)
5986 . expect ( "Failed to find the justifications index to set" ) ;
87+
6088 self . justifications_roots_validators
61- . set ( index * U262144 :: to_usize ( ) + * validator_id as usize , value)
89+ . set (
90+ index * VALIDATOR_REGISTRY_LIMIT as usize + * validator_id as usize ,
91+ value,
92+ )
6293 . expect ( "Failed to set justification bit" ) ;
6394 }
6495
@@ -67,29 +98,201 @@ impl LeanState {
6798 . get_justifications_roots_index ( root)
6899 . expect ( "Could not find justifications for the provided block root" ) ;
69100
70- let ( start_range, end_range ) = self . get_justifications_roots_range ( & index) ;
101+ let start_range = index * VALIDATOR_REGISTRY_LIMIT as usize ;
71102
72- self . justifications_roots_validators . as_slice ( ) [ start_range..end_range ]
103+ self . justifications_roots_validators
73104 . iter ( )
105+ . skip ( start_range)
106+ . take ( VALIDATOR_REGISTRY_LIMIT as usize )
74107 . fold ( 0 , |acc, justification_bits| {
75- acc + justification_bits. count_ones ( )
108+ acc + justification_bits as usize
76109 } ) as u64
77110 }
78111
79112 pub fn remove_justifications ( & mut self , root : & B256 ) {
80- // Remove from `state.justifications_roots`
81113 let index = self
82114 . get_justifications_roots_index ( root)
83115 . expect ( "Failed to find the justifications index to remove" ) ;
84116 self . justifications_roots . remove ( index) ;
85117
86- let ( start_range, end_range) = self . get_justifications_roots_range ( & index) ;
118+ let new_length = self . justifications_roots . len ( ) * VALIDATOR_REGISTRY_LIMIT as usize ;
119+ let mut new_justifications_roots_validators =
120+ BitList :: < U1073741824 > :: with_capacity ( new_length)
121+ . expect ( "Failed to recreate state's justifications_roots_validators" ) ;
87122
88- // Remove from `state.justifications_roots_validators`
89- for i in start_range..end_range {
90- self . justifications_roots_validators
91- . set ( i, false )
92- . expect ( "Failed to remove justifications" ) ;
93- }
123+ // Take left side of the list (if any)
124+ self . justifications_roots_validators
125+ . iter ( )
126+ . take ( index * VALIDATOR_REGISTRY_LIMIT as usize )
127+ . fold ( 0 , |i, justification_bit| {
128+ new_justifications_roots_validators
129+ . set ( i, justification_bit)
130+ . expect ( "Failed to set new justification bit" ) ;
131+ i + 1
132+ } ) ;
133+
134+ // Take right side of the list (if any)
135+ self . justifications_roots_validators
136+ . iter ( )
137+ . skip ( ( index + 1 ) * VALIDATOR_REGISTRY_LIMIT as usize )
138+ . fold (
139+ index * VALIDATOR_REGISTRY_LIMIT as usize ,
140+ |i, justification_bit| {
141+ new_justifications_roots_validators
142+ . set ( i, justification_bit)
143+ . expect ( "Failed to set new justification bit" ) ;
144+ i + 1
145+ } ,
146+ ) ;
147+
148+ self . justifications_roots_validators = new_justifications_roots_validators;
149+ }
150+ }
151+
152+ #[ cfg( test) ]
153+ mod test {
154+ use super :: * ;
155+
156+ #[ test]
157+ fn initialize_justifications_for_root ( ) {
158+ let mut state = LeanState :: new ( 1 ) ;
159+
160+ // Initialize 1st root
161+ state. initialize_justifications_for_root ( & B256 :: repeat_byte ( 1 ) ) ;
162+ assert_eq ! ( state. justifications_roots. len( ) , 1 ) ;
163+ assert_eq ! (
164+ state. justifications_roots_validators. len( ) ,
165+ VALIDATOR_REGISTRY_LIMIT as usize
166+ ) ;
167+
168+ // Initialize an existing root should result in same lengths
169+ state. initialize_justifications_for_root ( & B256 :: repeat_byte ( 1 ) ) ;
170+ assert_eq ! ( state. justifications_roots. len( ) , 1 ) ;
171+ assert_eq ! (
172+ state. justifications_roots_validators. len( ) ,
173+ VALIDATOR_REGISTRY_LIMIT as usize
174+ ) ;
175+
176+ // Initialize 2nd root
177+ state. initialize_justifications_for_root ( & B256 :: repeat_byte ( 2 ) ) ;
178+ assert_eq ! ( state. justifications_roots. len( ) , 2 ) ;
179+ assert_eq ! (
180+ state. justifications_roots_validators. len( ) ,
181+ 2 * VALIDATOR_REGISTRY_LIMIT as usize
182+ ) ;
183+ }
184+
185+ #[ test]
186+ fn set_justification ( ) {
187+ let mut state = LeanState :: new ( 1 ) ;
188+ let root0 = B256 :: repeat_byte ( 1 ) ;
189+ let root1 = B256 :: repeat_byte ( 2 ) ;
190+ let validator_id = 7u64 ;
191+
192+ // Set for 1st root
193+ state. initialize_justifications_for_root ( & root0) ;
194+ state. set_justification ( & root0, & validator_id, true ) ;
195+ assert ! (
196+ state
197+ . justifications_roots_validators
198+ . get( validator_id as usize )
199+ . unwrap( )
200+ ) ;
201+
202+ // Set for 2nd root
203+ state. initialize_justifications_for_root ( & root1) ;
204+ state. set_justification ( & root1, & validator_id, true ) ;
205+ assert ! (
206+ state
207+ . justifications_roots_validators
208+ . get( VALIDATOR_REGISTRY_LIMIT as usize + validator_id as usize )
209+ . unwrap( )
210+ ) ;
211+ }
212+
213+ #[ test]
214+ fn count_justifications ( ) {
215+ let mut state = LeanState :: new ( 1 ) ;
216+ let root0 = B256 :: repeat_byte ( 1 ) ;
217+ let root1 = B256 :: repeat_byte ( 2 ) ;
218+
219+ // Justifications for 1st root, up to 2 justifications
220+ state. initialize_justifications_for_root ( & root0) ;
221+
222+ state. set_justification ( & root0, & 1u64 , true ) ;
223+ assert_eq ! ( state. count_justifications( & root0) , 1 ) ;
224+
225+ state. set_justification ( & root0, & 2u64 , true ) ;
226+ assert_eq ! ( state. count_justifications( & root0) , 2 ) ;
227+
228+ // Justifications for 2nd root, up to 3 justifications
229+ state. initialize_justifications_for_root ( & root1) ;
230+
231+ state. set_justification ( & root1, & 11u64 , true ) ;
232+ assert_eq ! ( state. count_justifications( & root1) , 1 ) ;
233+
234+ state. set_justification ( & root1, & 22u64 , true ) ;
235+ state. set_justification ( & root1, & 33u64 , true ) ;
236+ assert_eq ! ( state. count_justifications( & root1) , 3 ) ;
237+ }
238+
239+ #[ test]
240+ fn remove_justifications ( ) {
241+ // Assuming 3 roots & 4 validators
242+ let mut state = LeanState :: new ( 3 ) ;
243+ let root0 = B256 :: repeat_byte ( 1 ) ;
244+ let root1 = B256 :: repeat_byte ( 2 ) ;
245+ let root2 = B256 :: repeat_byte ( 3 ) ;
246+
247+ // Add justifications for left root
248+ state. initialize_justifications_for_root ( & root0) ;
249+ state. set_justification ( & root0, & 0u64 , true ) ;
250+
251+ // Add justifications for middle root
252+ state. initialize_justifications_for_root ( & root1) ;
253+ state. set_justification ( & root1, & 1u64 , true ) ;
254+
255+ // Add justifications for last root
256+ state. initialize_justifications_for_root ( & root2) ;
257+ state. set_justification ( & root2, & 2u64 , true ) ;
258+
259+ // Assert before removal
260+ assert_eq ! ( state. justifications_roots. len( ) , 3 ) ;
261+ assert_eq ! (
262+ state. justifications_roots_validators. len( ) ,
263+ 3 * VALIDATOR_REGISTRY_LIMIT as usize
264+ ) ;
265+
266+ // Assert after removing middle root (root1)
267+ state. remove_justifications ( & root1) ;
268+
269+ assert_eq ! (
270+ state. get_justifications_roots_index( & root1) ,
271+ None ,
272+ "Root still exists after removal"
273+ ) ;
274+ assert_eq ! (
275+ state. justifications_roots. len( ) ,
276+ 2 ,
277+ "Should be reduced by 1"
278+ ) ;
279+ assert_eq ! (
280+ state. justifications_roots_validators. len( ) ,
281+ 2 * VALIDATOR_REGISTRY_LIMIT as usize ,
282+ "Should be reduced by VALIDATOR_REGISTRY_LIMIT"
283+ ) ;
284+
285+ // Assert justifications
286+ assert ! (
287+ state. justifications_roots_validators. get( 0 ) . unwrap( ) ,
288+ "root0 should still be justified by validator0"
289+ ) ;
290+ assert ! (
291+ state
292+ . justifications_roots_validators
293+ . get( VALIDATOR_REGISTRY_LIMIT as usize + 2 )
294+ . unwrap( ) ,
295+ "root2 should still be justified by validator2"
296+ ) ;
94297 }
95298}
0 commit comments