@@ -66,6 +66,34 @@ pub struct CertificateRecord {
66
66
pub sealed_at : String ,
67
67
}
68
68
69
+ impl CertificateRecord {
70
+ #[ cfg( test) ]
71
+ pub fn dummy_genesis ( id : & str , beacon : Beacon ) -> Self {
72
+ let mut record = Self :: dummy ( id, "" , beacon) ;
73
+ record. parent_certificate_id = None ;
74
+ record
75
+ }
76
+
77
+ #[ cfg( test) ]
78
+ pub fn dummy ( id : & str , parent_id : & str , beacon : Beacon ) -> Self {
79
+ Self {
80
+ certificate_id : id. to_string ( ) ,
81
+ parent_certificate_id : Some ( parent_id. to_string ( ) ) ,
82
+ message : "message" . to_string ( ) ,
83
+ signature : "signature" . to_string ( ) ,
84
+ aggregate_verification_key : "avk" . to_string ( ) ,
85
+ epoch : beacon. epoch ,
86
+ beacon,
87
+ protocol_version : "protocol_version" . to_string ( ) ,
88
+ protocol_parameters : Default :: default ( ) ,
89
+ protocol_message : Default :: default ( ) ,
90
+ signers : vec ! [ ] ,
91
+ initiated_at : "???" . to_string ( ) ,
92
+ sealed_at : "???" . to_string ( ) ,
93
+ }
94
+ }
95
+ }
96
+
69
97
impl From < Certificate > for CertificateRecord {
70
98
fn from ( other : Certificate ) -> Self {
71
99
if !other. genesis_signature . is_empty ( ) {
@@ -401,17 +429,11 @@ impl<'conn> MasterCertificateProvider<'conn> {
401
429
}
402
430
403
431
pub fn get_master_certificate_condition ( & self , epoch : Epoch ) -> WhereCondition {
404
- let condition =
405
- WhereCondition :: new ( "certificate.parent_certificate_id is null" , Vec :: new ( ) ) . or_where (
406
- WhereCondition :: new ( "parent_certificate.epoch != certificate.epoch" , Vec :: new ( ) ) ,
407
- ) ;
408
-
409
432
let epoch_i64: i64 = epoch. 0 . try_into ( ) . unwrap ( ) ;
410
433
WhereCondition :: new (
411
434
"certificate.epoch between ?* and ?*" ,
412
435
vec ! [ Value :: Integer ( epoch_i64 - 1 ) , Value :: Integer ( epoch_i64) ] ,
413
436
)
414
- . and_where ( condition)
415
437
}
416
438
}
417
439
@@ -425,18 +447,15 @@ impl<'conn> Provider<'conn> for MasterCertificateProvider<'conn> {
425
447
fn get_definition ( & self , condition : & str ) -> String {
426
448
// it is important to alias the fields with the same name as the table
427
449
// since the table cannot be aliased in a RETURNING statement in SQLite.
428
- let projection = Self :: Entity :: get_projection ( ) . expand ( SourceAlias :: new ( & [
429
- ( "{:certificate:}" , "certificate" ) ,
430
- ( "{:parent_certificate:}" , "parent_certificate" ) ,
431
- ] ) ) ;
450
+ let projection = Self :: Entity :: get_projection ( )
451
+ . expand ( SourceAlias :: new ( & [ ( "{:certificate:}" , "certificate" ) ] ) ) ;
432
452
433
453
format ! (
434
454
r#"
435
455
select {projection}
436
456
from certificate
437
- left join certificate as parent_certificate
438
- on certificate.parent_certificate_id = parent_certificate.certificate_id
439
- where {condition}"#
457
+ where {condition}
458
+ group by certificate.epoch order by certificate.epoch desc, certificate.ROWID asc"#
440
459
)
441
460
}
442
461
}
@@ -872,7 +891,10 @@ mod tests {
872
891
let condition = provider. get_master_certificate_condition ( Epoch ( 10 ) ) ;
873
892
let ( condition_str, parameters) = condition. expand ( ) ;
874
893
875
- assert_eq ! ( "certificate.epoch between ?1 and ?2 and (certificate.parent_certificate_id is null or parent_certificate.epoch != certificate.epoch)" . to_string( ) , condition_str) ;
894
+ assert_eq ! (
895
+ "certificate.epoch between ?1 and ?2" . to_string( ) ,
896
+ condition_str
897
+ ) ;
876
898
assert_eq ! ( vec![ Value :: Integer ( 9 ) , Value :: Integer ( 10 ) ] , parameters) ;
877
899
}
878
900
@@ -904,6 +926,168 @@ mod tests {
904
926
assert_eq ! ( expected_hash, certificate. hash) ;
905
927
}
906
928
929
+ async fn insert_certificate_records (
930
+ connection : Arc < Mutex < Connection > > ,
931
+ records : Vec < CertificateRecord > ,
932
+ ) {
933
+ let lock = connection. lock ( ) . await ;
934
+ let provider = InsertCertificateRecordProvider :: new ( & lock) ;
935
+
936
+ for certificate in records {
937
+ provider. persist ( certificate) . unwrap ( ) ;
938
+ }
939
+ }
940
+
941
+ #[ tokio:: test]
942
+ async fn get_master_certificate_no_certificate_recorded_returns_none ( ) {
943
+ let mut deps = DependenciesBuilder :: new ( Configuration :: new_sample ( ) ) ;
944
+ let connection = deps. get_sqlite_connection ( ) . await . unwrap ( ) ;
945
+ let certificates = vec ! [ ] ;
946
+ insert_certificate_records ( connection. clone ( ) , certificates) . await ;
947
+
948
+ let repository = CertificateRepository :: new ( connection) ;
949
+ let certificate = repository
950
+ . get_master_certificate_for_epoch ( Epoch ( 1 ) )
951
+ . await
952
+ . unwrap ( ) ;
953
+
954
+ assert_eq ! ( None , certificate) ;
955
+ }
956
+
957
+ #[ tokio:: test]
958
+ async fn get_master_certificate_one_cert_in_current_epoch_recorded_returns_that_one ( ) {
959
+ let mut deps = DependenciesBuilder :: new ( Configuration :: new_sample ( ) ) ;
960
+ let connection = deps. get_sqlite_connection ( ) . await . unwrap ( ) ;
961
+ let certificate = CertificateRecord :: dummy_genesis ( "1" , Beacon :: new ( String :: new ( ) , 1 , 1 ) ) ;
962
+ let expected_certificate: Certificate = certificate. clone ( ) . into ( ) ;
963
+ insert_certificate_records ( connection. clone ( ) , vec ! [ certificate] ) . await ;
964
+
965
+ let repository = CertificateRepository :: new ( connection) ;
966
+ let certificate = repository
967
+ . get_master_certificate_for_epoch ( Epoch ( 1 ) )
968
+ . await
969
+ . unwrap ( )
970
+ . expect ( "This should return a certificate." ) ;
971
+
972
+ assert_eq ! ( expected_certificate, certificate) ;
973
+ }
974
+
975
+ #[ tokio:: test]
976
+ async fn get_master_certificate_multiple_cert_in_current_epoch_returns_first_of_current_epoch ( )
977
+ {
978
+ let mut deps = DependenciesBuilder :: new ( Configuration :: new_sample ( ) ) ;
979
+ let connection = deps. get_sqlite_connection ( ) . await . unwrap ( ) ;
980
+ let certificates = vec ! [
981
+ CertificateRecord :: dummy_genesis( "1" , Beacon :: new( String :: new( ) , 1 , 1 ) ) ,
982
+ CertificateRecord :: dummy( "2" , "1" , Beacon :: new( String :: new( ) , 1 , 2 ) ) ,
983
+ CertificateRecord :: dummy( "3" , "1" , Beacon :: new( String :: new( ) , 1 , 3 ) ) ,
984
+ ] ;
985
+ let expected_certificate: Certificate = certificates. first ( ) . unwrap ( ) . clone ( ) . into ( ) ;
986
+ insert_certificate_records ( connection. clone ( ) , certificates) . await ;
987
+
988
+ let repository = CertificateRepository :: new ( connection) ;
989
+ let certificate = repository
990
+ . get_master_certificate_for_epoch ( Epoch ( 1 ) )
991
+ . await
992
+ . unwrap ( )
993
+ . expect ( "This should return a certificate." ) ;
994
+
995
+ assert_eq ! ( expected_certificate, certificate) ;
996
+ }
997
+
998
+ #[ tokio:: test]
999
+ async fn get_master_certificate_multiple_cert_in_previous_epoch_none_in_the_current_returns_first_of_previous_epoch (
1000
+ ) {
1001
+ let mut deps = DependenciesBuilder :: new ( Configuration :: new_sample ( ) ) ;
1002
+ let connection = deps. get_sqlite_connection ( ) . await . unwrap ( ) ;
1003
+ let certificates = vec ! [
1004
+ CertificateRecord :: dummy_genesis( "1" , Beacon :: new( String :: new( ) , 1 , 1 ) ) ,
1005
+ CertificateRecord :: dummy( "2" , "1" , Beacon :: new( String :: new( ) , 1 , 2 ) ) ,
1006
+ CertificateRecord :: dummy( "3" , "1" , Beacon :: new( String :: new( ) , 1 , 3 ) ) ,
1007
+ ] ;
1008
+ let expected_certificate: Certificate = certificates. first ( ) . unwrap ( ) . clone ( ) . into ( ) ;
1009
+ insert_certificate_records ( connection. clone ( ) , certificates) . await ;
1010
+
1011
+ let repository = CertificateRepository :: new ( connection) ;
1012
+ let certificate = repository
1013
+ . get_master_certificate_for_epoch ( Epoch ( 2 ) )
1014
+ . await
1015
+ . unwrap ( )
1016
+ . expect ( "This should return a certificate." ) ;
1017
+
1018
+ assert_eq ! ( expected_certificate, certificate) ;
1019
+ }
1020
+
1021
+ #[ tokio:: test]
1022
+ async fn get_master_certificate_multiple_cert_in_previous_one_cert_in_current_epoch_returns_one_in_current_epoch (
1023
+ ) {
1024
+ let mut deps = DependenciesBuilder :: new ( Configuration :: new_sample ( ) ) ;
1025
+ let connection = deps. get_sqlite_connection ( ) . await . unwrap ( ) ;
1026
+ let certificates = vec ! [
1027
+ CertificateRecord :: dummy_genesis( "1" , Beacon :: new( String :: new( ) , 1 , 1 ) ) ,
1028
+ CertificateRecord :: dummy( "2" , "1" , Beacon :: new( String :: new( ) , 1 , 2 ) ) ,
1029
+ CertificateRecord :: dummy( "3" , "1" , Beacon :: new( String :: new( ) , 1 , 3 ) ) ,
1030
+ CertificateRecord :: dummy( "4" , "1" , Beacon :: new( String :: new( ) , 2 , 4 ) ) ,
1031
+ ] ;
1032
+ let expected_certificate: Certificate = certificates. last ( ) . unwrap ( ) . clone ( ) . into ( ) ;
1033
+ insert_certificate_records ( connection. clone ( ) , certificates) . await ;
1034
+
1035
+ let repository = CertificateRepository :: new ( connection) ;
1036
+ let certificate = repository
1037
+ . get_master_certificate_for_epoch ( Epoch ( 2 ) )
1038
+ . await
1039
+ . unwrap ( )
1040
+ . expect ( "This should return a certificate." ) ;
1041
+
1042
+ assert_eq ! ( expected_certificate, certificate) ;
1043
+ }
1044
+
1045
+ #[ tokio:: test]
1046
+ async fn get_master_certificate_multiple_cert_in_previous_multiple_in_current_epoch_returns_first_of_current_epoch (
1047
+ ) {
1048
+ let mut deps = DependenciesBuilder :: new ( Configuration :: new_sample ( ) ) ;
1049
+ let connection = deps. get_sqlite_connection ( ) . await . unwrap ( ) ;
1050
+ let certificates = vec ! [
1051
+ CertificateRecord :: dummy_genesis( "1" , Beacon :: new( String :: new( ) , 1 , 1 ) ) ,
1052
+ CertificateRecord :: dummy( "2" , "1" , Beacon :: new( String :: new( ) , 1 , 2 ) ) ,
1053
+ CertificateRecord :: dummy( "3" , "1" , Beacon :: new( String :: new( ) , 1 , 3 ) ) ,
1054
+ CertificateRecord :: dummy( "4" , "1" , Beacon :: new( String :: new( ) , 2 , 4 ) ) ,
1055
+ CertificateRecord :: dummy( "5" , "4" , Beacon :: new( String :: new( ) , 2 , 5 ) ) ,
1056
+ CertificateRecord :: dummy( "6" , "4" , Beacon :: new( String :: new( ) , 2 , 6 ) ) ,
1057
+ ] ;
1058
+ let expected_certificate: Certificate = certificates. get ( 3 ) . unwrap ( ) . clone ( ) . into ( ) ;
1059
+ insert_certificate_records ( connection. clone ( ) , certificates) . await ;
1060
+
1061
+ let repository = CertificateRepository :: new ( connection) ;
1062
+ let certificate = repository
1063
+ . get_master_certificate_for_epoch ( Epoch ( 2 ) )
1064
+ . await
1065
+ . unwrap ( )
1066
+ . expect ( "This should return a certificate." ) ;
1067
+ assert_eq ! ( expected_certificate, certificate) ;
1068
+ }
1069
+
1070
+ #[ tokio:: test]
1071
+ async fn get_master_certificate_multiple_cert_in_penultimate_epoch_none_in_previous_returns_none (
1072
+ ) {
1073
+ let mut deps = DependenciesBuilder :: new ( Configuration :: new_sample ( ) ) ;
1074
+ let connection = deps. get_sqlite_connection ( ) . await . unwrap ( ) ;
1075
+ let certificates = vec ! [
1076
+ CertificateRecord :: dummy_genesis( "1" , Beacon :: new( String :: new( ) , 1 , 1 ) ) ,
1077
+ CertificateRecord :: dummy( "2" , "1" , Beacon :: new( String :: new( ) , 1 , 2 ) ) ,
1078
+ CertificateRecord :: dummy( "3" , "1" , Beacon :: new( String :: new( ) , 1 , 3 ) ) ,
1079
+ ] ;
1080
+ insert_certificate_records ( connection. clone ( ) , certificates) . await ;
1081
+
1082
+ let repository = CertificateRepository :: new ( connection) ;
1083
+ let certificate = repository
1084
+ . get_master_certificate_for_epoch ( Epoch ( 3 ) )
1085
+ . await
1086
+ . unwrap ( ) ;
1087
+
1088
+ assert_eq ! ( None , certificate) ;
1089
+ }
1090
+
907
1091
#[ tokio:: test]
908
1092
async fn get_master_certificate_for_epoch ( ) {
909
1093
let ( certificates, _) = setup_certificate_chain ( 3 , 1 ) ;
0 commit comments