@@ -8,7 +8,7 @@ const MITHRIL_SIGNER_VERSION_HEADER: &str = "signer-node-version";
8
8
pub fn routes (
9
9
dependency_manager : Arc < DependencyContainer > ,
10
10
) -> impl Filter < Extract = ( impl warp:: Reply , ) , Error = warp:: Rejection > + Clone {
11
- register_signer ( dependency_manager)
11
+ register_signer ( dependency_manager. clone ( ) ) . or ( registered_signers ( dependency_manager ) )
12
12
}
13
13
14
14
/// POST /register-signer
@@ -31,10 +31,22 @@ fn register_signer(
31
31
. and_then ( handlers:: register_signer)
32
32
}
33
33
34
+ /// Get /signers/registered/:epoch
35
+ fn registered_signers (
36
+ dependency_manager : Arc < DependencyContainer > ,
37
+ ) -> impl Filter < Extract = ( impl warp:: Reply , ) , Error = warp:: Rejection > + Clone {
38
+ warp:: path!( "signers" / "registered" / String )
39
+ . and ( warp:: get ( ) )
40
+ . and ( middlewares:: with_verification_key_store ( dependency_manager) )
41
+ . and_then ( handlers:: registered_signers)
42
+ }
43
+
34
44
mod handlers {
45
+ use crate :: entities:: SignerRegistrationsMessage ;
35
46
use crate :: event_store:: { EventMessage , TransmitterService } ;
36
- use crate :: FromRegisterSignerAdapter ;
37
47
use crate :: { http_server:: routes:: reply, SignerRegisterer , SignerRegistrationError } ;
48
+ use crate :: { FromRegisterSignerAdapter , VerificationKeyStorer } ;
49
+ use mithril_common:: entities:: Epoch ;
38
50
use mithril_common:: messages:: { RegisterSignerMessage , TryFromMessageAdapter } ;
39
51
use mithril_common:: BeaconProvider ;
40
52
use slog_scope:: { debug, warn} ;
@@ -139,21 +151,68 @@ mod handlers {
139
151
}
140
152
}
141
153
}
154
+
155
+ /// Get Registered Signers for a given epoch
156
+ pub async fn registered_signers (
157
+ registered_at : String ,
158
+ verification_key_store : Arc < dyn VerificationKeyStorer > ,
159
+ ) -> Result < impl warp:: Reply , Infallible > {
160
+ debug ! ( "⇄ HTTP SERVER: signers/registered/{:?}" , registered_at) ;
161
+
162
+ let registered_at = match registered_at. parse :: < u64 > ( ) {
163
+ Ok ( epoch) => Epoch ( epoch) ,
164
+ Err ( err) => {
165
+ warn ! ( "registered_signers::invalid_epoch" ; "error" => ?err) ;
166
+ return Ok ( reply:: bad_request (
167
+ "invalid_epoch" . to_string ( ) ,
168
+ err. to_string ( ) ,
169
+ ) ) ;
170
+ }
171
+ } ;
172
+
173
+ // The given epoch is the epoch at which the signer registered, the store works on
174
+ // the recording epoch so we need to offset.
175
+ match verification_key_store
176
+ . get_stake_distribution_for_epoch ( registered_at. offset_to_recording_epoch ( ) )
177
+ . await
178
+ {
179
+ Ok ( Some ( stake_distribution) ) => {
180
+ let message = SignerRegistrationsMessage :: new ( registered_at, stake_distribution) ;
181
+ Ok ( reply:: json ( & message, StatusCode :: OK ) )
182
+ }
183
+ Ok ( None ) => {
184
+ warn ! ( "registered_signers::not_found" ) ;
185
+ Ok ( reply:: empty ( StatusCode :: NOT_FOUND ) )
186
+ }
187
+ Err ( err) => {
188
+ warn ! ( "registered_signers::error" ; "error" => ?err) ;
189
+ Ok ( reply:: internal_server_error ( err. to_string ( ) ) )
190
+ }
191
+ }
192
+ }
142
193
}
143
194
144
195
#[ cfg( test) ]
145
196
mod tests {
146
- use mithril_common:: crypto_helper:: ProtocolRegistrationError ;
147
- use mithril_common:: messages:: RegisterSignerMessage ;
148
- use mithril_common:: test_utils:: apispec:: APISpec ;
149
- use mithril_common:: test_utils:: fake_data;
150
- use warp:: http:: Method ;
151
- use warp:: test:: request;
197
+ use mithril_common:: entities:: Epoch ;
198
+ use mithril_common:: {
199
+ crypto_helper:: ProtocolRegistrationError ,
200
+ entities:: StakeDistribution ,
201
+ messages:: RegisterSignerMessage ,
202
+ store:: adapter:: AdapterError ,
203
+ test_utils:: { apispec:: APISpec , fake_data} ,
204
+ } ;
205
+ use mockall:: predicate:: eq;
206
+ use serde_json:: Value :: Null ;
207
+ use warp:: { http:: Method , test:: request} ;
208
+
209
+ use crate :: {
210
+ http_server:: SERVER_BASE_PATH , initialize_dependencies,
211
+ signer_registerer:: MockSignerRegisterer , store:: MockVerificationKeyStorer ,
212
+ SignerRegistrationError ,
213
+ } ;
152
214
153
215
use super :: * ;
154
- use crate :: http_server:: SERVER_BASE_PATH ;
155
- use crate :: signer_registerer:: MockSignerRegisterer ;
156
- use crate :: { initialize_dependencies, SignerRegistrationError } ;
157
216
158
217
fn setup_router (
159
218
dependency_manager : Arc < DependencyContainer > ,
@@ -316,4 +375,128 @@ mod tests {
316
375
& response,
317
376
) ;
318
377
}
378
+
379
+ #[ tokio:: test]
380
+ async fn test_registered_signers_get_offset_given_epoch_to_registration_epoch ( ) {
381
+ let asked_epoch = Epoch ( 1 ) ;
382
+ let expected_retrieval_epoch = asked_epoch. offset_to_recording_epoch ( ) ;
383
+ let stake_distribution = StakeDistribution :: from_iter (
384
+ fake_data:: signers_with_stakes ( 3 )
385
+ . into_iter ( )
386
+ . map ( |s| ( s. party_id , s. stake ) ) ,
387
+ ) ;
388
+ let mut mock_verification_key_store = MockVerificationKeyStorer :: new ( ) ;
389
+ mock_verification_key_store
390
+ . expect_get_stake_distribution_for_epoch ( )
391
+ . with ( eq ( expected_retrieval_epoch) )
392
+ . return_once ( |_| Ok ( Some ( stake_distribution) ) )
393
+ . once ( ) ;
394
+ let mut dependency_manager = initialize_dependencies ( ) . await ;
395
+ dependency_manager. verification_key_store = Arc :: new ( mock_verification_key_store) ;
396
+
397
+ let method = Method :: GET . as_str ( ) ;
398
+ let base_path = "/signers/registered" ;
399
+
400
+ let response = request ( )
401
+ . method ( method)
402
+ . path ( & format ! ( "/{SERVER_BASE_PATH}{base_path}/{}" , asked_epoch) )
403
+ . reply ( & setup_router ( Arc :: new ( dependency_manager) ) )
404
+ . await ;
405
+
406
+ assert ! (
407
+ response. status( ) . is_success( ) ,
408
+ "expected the response to succeed, was: {response:#?}"
409
+ ) ;
410
+ }
411
+
412
+ #[ tokio:: test]
413
+ async fn test_registered_signers_get_ok ( ) {
414
+ let stake_distribution = StakeDistribution :: from_iter (
415
+ fake_data:: signers_with_stakes ( 3 )
416
+ . into_iter ( )
417
+ . map ( |s| ( s. party_id , s. stake ) ) ,
418
+ ) ;
419
+ let mut mock_verification_key_store = MockVerificationKeyStorer :: new ( ) ;
420
+ mock_verification_key_store
421
+ . expect_get_stake_distribution_for_epoch ( )
422
+ . return_once ( |_| Ok ( Some ( stake_distribution) ) )
423
+ . once ( ) ;
424
+ let mut dependency_manager = initialize_dependencies ( ) . await ;
425
+ dependency_manager. verification_key_store = Arc :: new ( mock_verification_key_store) ;
426
+
427
+ let base_path = "/signers/registered" ;
428
+ let method = Method :: GET . as_str ( ) ;
429
+
430
+ let response = request ( )
431
+ . method ( method)
432
+ . path ( & format ! ( "/{SERVER_BASE_PATH}{base_path}/1" ) )
433
+ . reply ( & setup_router ( Arc :: new ( dependency_manager) ) )
434
+ . await ;
435
+
436
+ APISpec :: verify_conformity (
437
+ APISpec :: get_all_spec_files ( ) ,
438
+ method,
439
+ & format ! ( "{base_path}/{{epoch}}" ) ,
440
+ "application/json" ,
441
+ & Null ,
442
+ & response,
443
+ ) ;
444
+ }
445
+
446
+ #[ tokio:: test]
447
+ async fn test_registered_signers_get_ok_noregistration ( ) {
448
+ let mut mock_verification_key_store = MockVerificationKeyStorer :: new ( ) ;
449
+ mock_verification_key_store
450
+ . expect_get_stake_distribution_for_epoch ( )
451
+ . return_once ( |_| Ok ( None ) )
452
+ . once ( ) ;
453
+ let mut dependency_manager = initialize_dependencies ( ) . await ;
454
+ dependency_manager. verification_key_store = Arc :: new ( mock_verification_key_store) ;
455
+
456
+ let method = Method :: GET . as_str ( ) ;
457
+ let base_path = "/signers/registered" ;
458
+
459
+ let response = request ( )
460
+ . method ( method)
461
+ . path ( & format ! ( "/{SERVER_BASE_PATH}{base_path}/3" ) )
462
+ . reply ( & setup_router ( Arc :: new ( dependency_manager) ) )
463
+ . await ;
464
+
465
+ APISpec :: verify_conformity (
466
+ APISpec :: get_all_spec_files ( ) ,
467
+ method,
468
+ & format ! ( "{base_path}/{{epoch}}" ) ,
469
+ "application/json" ,
470
+ & Null ,
471
+ & response,
472
+ ) ;
473
+ }
474
+
475
+ #[ tokio:: test]
476
+ async fn test_registered_signers_get_ko ( ) {
477
+ let mut mock_verification_key_store = MockVerificationKeyStorer :: new ( ) ;
478
+ mock_verification_key_store
479
+ . expect_get_stake_distribution_for_epoch ( )
480
+ . return_once ( |_| Err ( AdapterError :: GeneralError ( "invalid query" . to_string ( ) ) . into ( ) ) ) ;
481
+ let mut dependency_manager = initialize_dependencies ( ) . await ;
482
+ dependency_manager. verification_key_store = Arc :: new ( mock_verification_key_store) ;
483
+
484
+ let method = Method :: GET . as_str ( ) ;
485
+ let base_path = "/signers/registered" ;
486
+
487
+ let response = request ( )
488
+ . method ( method)
489
+ . path ( & format ! ( "/{SERVER_BASE_PATH}{base_path}/1" ) )
490
+ . reply ( & setup_router ( Arc :: new ( dependency_manager) ) )
491
+ . await ;
492
+
493
+ APISpec :: verify_conformity (
494
+ APISpec :: get_all_spec_files ( ) ,
495
+ method,
496
+ & format ! ( "{base_path}/{{epoch}}" ) ,
497
+ "application/json" ,
498
+ & Null ,
499
+ & response,
500
+ ) ;
501
+ }
319
502
}
0 commit comments