@@ -108,4 +108,178 @@ pub fn getVoluntaryExitValidity(
108108 return .valid ;
109109}
110110
111- // TODO: unit test
111+ const std = @import ("std" );
112+ const TestCachedBeaconState = @import ("../test_utils/root.zig" ).TestCachedBeaconState ;
113+ const Node = @import ("persistent_merkle_tree" ).Node ;
114+ const preset = @import ("preset" ).preset ;
115+
116+ fn makeSignedVoluntaryExit (epoch : u64 , validator_index : u64 ) SignedVoluntaryExit {
117+ return .{
118+ .message = .{
119+ .epoch = epoch ,
120+ .validator_index = validator_index ,
121+ },
122+ .signature = [_ ]u8 {0 } ** 96 ,
123+ };
124+ }
125+
126+ test "voluntary exit - valid" {
127+ const allocator = std .testing .allocator ;
128+ const pool_size = 256 * 5 ;
129+ var pool = try Node .Pool .init (allocator , pool_size );
130+ defer pool .deinit ();
131+
132+ var test_state = try TestCachedBeaconState .init (allocator , & pool , 256 );
133+ defer test_state .deinit ();
134+
135+ const current_epoch = test_state .cached_state .epoch_cache .epoch ;
136+ const signed_exit = makeSignedVoluntaryExit (current_epoch , 0 );
137+
138+ const result = try getVoluntaryExitValidity (
139+ .electra ,
140+ test_state .config ,
141+ test_state .cached_state .epoch_cache ,
142+ test_state .cached_state .state .castToFork (.electra ),
143+ & signed_exit ,
144+ false ,
145+ );
146+ try std .testing .expectEqual (.valid , result );
147+ }
148+
149+ test "voluntary exit - inactive validator (out of bounds index)" {
150+ const allocator = std .testing .allocator ;
151+ const pool_size = 256 * 5 ;
152+ var pool = try Node .Pool .init (allocator , pool_size );
153+ defer pool .deinit ();
154+
155+ var test_state = try TestCachedBeaconState .init (allocator , & pool , 256 );
156+ defer test_state .deinit ();
157+
158+ const current_epoch = test_state .cached_state .epoch_cache .epoch ;
159+ const signed_exit = makeSignedVoluntaryExit (current_epoch , 9999 );
160+
161+ const result = try getVoluntaryExitValidity (
162+ .electra ,
163+ test_state .config ,
164+ test_state .cached_state .epoch_cache ,
165+ test_state .cached_state .state .castToFork (.electra ),
166+ & signed_exit ,
167+ false ,
168+ );
169+ try std .testing .expectEqual (.inactive , result );
170+ }
171+
172+ test "voluntary exit - inactive validator (not active in current epoch)" {
173+ const allocator = std .testing .allocator ;
174+ const pool_size = 256 * 5 ;
175+ var pool = try Node .Pool .init (allocator , pool_size );
176+ defer pool .deinit ();
177+
178+ var test_state = try TestCachedBeaconState .init (allocator , & pool , 256 );
179+ defer test_state .deinit ();
180+
181+ const current_epoch = test_state .cached_state .epoch_cache .epoch ;
182+
183+ // Set validator 0's exit_epoch to 0 so it's not active in current epoch
184+ var state = test_state .cached_state .state .castToFork (.electra );
185+ var validators = try state .validators ();
186+ var validator = try validators .get (0 );
187+ try validator .set ("exit_epoch" , 0 );
188+
189+ const signed_exit = makeSignedVoluntaryExit (current_epoch , 0 );
190+
191+ const result = try getVoluntaryExitValidity (
192+ .electra ,
193+ test_state .config ,
194+ test_state .cached_state .epoch_cache ,
195+ state ,
196+ & signed_exit ,
197+ false ,
198+ );
199+ try std .testing .expectEqual (.inactive , result );
200+ }
201+
202+ test "voluntary exit - already exited validator" {
203+ const allocator = std .testing .allocator ;
204+ const pool_size = 256 * 5 ;
205+ var pool = try Node .Pool .init (allocator , pool_size );
206+ defer pool .deinit ();
207+
208+ var test_state = try TestCachedBeaconState .init (allocator , & pool , 256 );
209+ defer test_state .deinit ();
210+
211+ const current_epoch = test_state .cached_state .epoch_cache .epoch ;
212+
213+ // Set validator 0's exit_epoch to a non-FAR_FUTURE value but still active
214+ var state = test_state .cached_state .state .castToFork (.electra );
215+ var validators = try state .validators ();
216+ var validator = try validators .get (0 );
217+ try validator .set ("exit_epoch" , current_epoch + 100 );
218+
219+ const signed_exit = makeSignedVoluntaryExit (current_epoch , 0 );
220+
221+ const result = try getVoluntaryExitValidity (
222+ .electra ,
223+ test_state .config ,
224+ test_state .cached_state .epoch_cache ,
225+ state ,
226+ & signed_exit ,
227+ false ,
228+ );
229+ try std .testing .expectEqual (.already_exited , result );
230+ }
231+
232+ test "voluntary exit - early epoch" {
233+ const allocator = std .testing .allocator ;
234+ const pool_size = 256 * 5 ;
235+ var pool = try Node .Pool .init (allocator , pool_size );
236+ defer pool .deinit ();
237+
238+ var test_state = try TestCachedBeaconState .init (allocator , & pool , 256 );
239+ defer test_state .deinit ();
240+
241+ const current_epoch = test_state .cached_state .epoch_cache .epoch ;
242+
243+ // Set voluntary exit epoch to a future epoch
244+ const signed_exit = makeSignedVoluntaryExit (current_epoch + 1 , 0 );
245+
246+ const result = try getVoluntaryExitValidity (
247+ .electra ,
248+ test_state .config ,
249+ test_state .cached_state .epoch_cache ,
250+ test_state .cached_state .state .castToFork (.electra ),
251+ & signed_exit ,
252+ false ,
253+ );
254+ try std .testing .expectEqual (.early_epoch , result );
255+ }
256+
257+ test "voluntary exit - short time active" {
258+ const allocator = std .testing .allocator ;
259+ const pool_size = 256 * 5 ;
260+ var pool = try Node .Pool .init (allocator , pool_size );
261+ defer pool .deinit ();
262+
263+ var test_state = try TestCachedBeaconState .init (allocator , & pool , 256 );
264+ defer test_state .deinit ();
265+
266+ const current_epoch = test_state .cached_state .epoch_cache .epoch ;
267+
268+ // Set validator 0's activation_epoch so it hasn't been active long enough
269+ var state = test_state .cached_state .state .castToFork (.electra );
270+ var validators = try state .validators ();
271+ var validator = try validators .get (0 );
272+ try validator .set ("activation_epoch" , current_epoch );
273+
274+ const signed_exit = makeSignedVoluntaryExit (current_epoch , 0 );
275+
276+ const result = try getVoluntaryExitValidity (
277+ .electra ,
278+ test_state .config ,
279+ test_state .cached_state .epoch_cache ,
280+ state ,
281+ & signed_exit ,
282+ false ,
283+ );
284+ try std .testing .expectEqual (.short_time_active , result );
285+ }
0 commit comments