1212//! - if valid, store it in an in-memory FIFO list
1313//! - if invalid, abort with an `Err`
1414//! 3. Repeat step 2. with each parent of the certificate until the genesis certificate is reached
15- //! 4. Store the fetched certificates in the database, for each certificate:
15+ //! 4. Store the fetched certificates in the database, from genesis to latest, for each certificate:
1616//! - if it exists in the database, it is replaced
1717//! - if it doesn't exist, it is inserted
1818//! 5. End
1919//!
2020use anyhow:: { Context , anyhow} ;
2121use async_trait:: async_trait;
2222use slog:: { Logger , debug, info} ;
23+ use std:: collections:: VecDeque ;
2324use std:: sync:: Arc ;
2425
2526use mithril_common:: StdResult ;
@@ -106,7 +107,9 @@ impl MithrilCertificateChainSynchronizer {
106107 & self ,
107108 starting_point : Certificate ,
108109 ) -> StdResult < Vec < Certificate > > {
109- let mut validated_certificates = Vec :: new ( ) ;
110+ // IMPORTANT: Order matters, certificates must be ordered from genesis to latest
111+ // (fetched database data is returned from last inserted to oldest)
112+ let mut validated_certificates = VecDeque :: new ( ) ;
110113 let mut certificate = starting_point;
111114
112115 loop {
@@ -117,7 +120,7 @@ impl MithrilCertificateChainSynchronizer {
117120 . with_context (
118121 || format ! ( "Failed to verify certificate: `{}`" , certificate. hash, ) ,
119122 ) ?;
120- validated_certificates. push ( certificate) ;
123+ validated_certificates. push_front ( certificate) ;
121124
122125 match parent_certificate {
123126 None => break ,
@@ -127,7 +130,7 @@ impl MithrilCertificateChainSynchronizer {
127130 }
128131 }
129132
130- Ok ( validated_certificates)
133+ Ok ( validated_certificates. into ( ) )
131134 }
132135
133136 async fn store_certificate_chain ( & self , certificate_chain : Vec < Certificate > ) -> StdResult < ( ) > {
@@ -445,6 +448,8 @@ mod tests {
445448 }
446449
447450 mod retrieve_validate_remote_certificate_chain {
451+ use mockall:: predicate:: { always, eq} ;
452+
448453 use super :: * ;
449454
450455 #[ tokio:: test]
@@ -494,9 +499,58 @@ mod tests {
494499 . await
495500 . unwrap ( ) ;
496501
497- let expected = chain. certificate_path_to_genesis ( & starting_point. hash ) ;
502+ let mut expected = chain. certificate_path_to_genesis ( & starting_point. hash ) ;
503+ expected. reverse ( ) ;
498504 assert_eq ! ( remote_certificate_chain, expected) ;
499505 }
506+
507+ #[ tokio:: test]
508+ async fn return_chain_ordered_from_genesis_to_latest ( ) {
509+ let base_certificate = fake_data:: certificate ( "whatever" ) ;
510+ let chain = vec ! [
511+ fake_data:: genesis_certificate( "genesis" ) ,
512+ Certificate {
513+ hash: "hash1" . to_string( ) ,
514+ previous_hash: "genesis" . to_string( ) ,
515+ ..base_certificate. clone( )
516+ } ,
517+ Certificate {
518+ hash: "hash2" . to_string( ) ,
519+ previous_hash: "hash1" . to_string( ) ,
520+ ..base_certificate
521+ } ,
522+ ] ;
523+ let synchroniser = MithrilCertificateChainSynchronizer {
524+ certificate_verifier : MockBuilder :: < MockCertificateVerifier > :: configure ( |mock| {
525+ let cert_1 = chain[ 1 ] . clone ( ) ;
526+ mock. expect_verify_certificate ( )
527+ . with ( eq ( chain[ 2 ] . clone ( ) ) , always ( ) )
528+ . return_once ( move |_, _| Ok ( Some ( cert_1) ) ) ;
529+ let genesis = chain[ 0 ] . clone ( ) ;
530+ mock. expect_verify_certificate ( )
531+ . with ( eq ( chain[ 1 ] . clone ( ) ) , always ( ) )
532+ . return_once ( move |_, _| Ok ( Some ( genesis) ) ) ;
533+ mock. expect_verify_certificate ( )
534+ . with ( eq ( chain[ 0 ] . clone ( ) ) , always ( ) )
535+ . return_once ( move |_, _| Ok ( None ) ) ;
536+ } ) ,
537+ ..MithrilCertificateChainSynchronizer :: default_for_test ( )
538+ } ;
539+
540+ let starting_point = chain[ 2 ] . clone ( ) ;
541+ let remote_certificate_chain = synchroniser
542+ . retrieve_and_validate_remote_certificate_chain ( starting_point. clone ( ) )
543+ . await
544+ . unwrap ( ) ;
545+
546+ assert_eq ! (
547+ remote_certificate_chain
548+ . into_iter( )
549+ . map( |c| c. hash)
550+ . collect:: <Vec <_>>( ) ,
551+ vec![ "genesis" . to_string( ) , "hash1" . to_string( ) , "hash2" . to_string( ) ]
552+ ) ;
553+ }
500554 }
501555
502556 mod store_remote_certificate_chain {
@@ -579,10 +633,10 @@ mod tests {
579633 // Will sync even if force is false
580634 synchroniser. synchronize_certificate_chain ( false ) . await . unwrap ( ) ;
581635
582- assert_eq ! (
583- remote_chain. certificate_path_to_genesis( & remote_chain. latest_certificate( ) . hash) ,
584- storer . stored_certificates ( )
585- ) ;
636+ let mut expected =
637+ remote_chain. certificate_path_to_genesis ( & remote_chain. latest_certificate ( ) . hash ) ;
638+ expected . reverse ( ) ;
639+ assert_eq ! ( expected , storer . stored_certificates ( ) ) ;
586640 }
587641
588642 #[ tokio:: test]
@@ -607,10 +661,10 @@ mod tests {
607661 // Force true - will sync
608662 synchroniser. synchronize_certificate_chain ( true ) . await . unwrap ( ) ;
609663
610- assert_eq ! (
611- remote_chain. certificate_path_to_genesis( & remote_chain. latest_certificate( ) . hash) ,
612- storer . stored_certificates ( )
613- ) ;
664+ let mut expected =
665+ remote_chain. certificate_path_to_genesis ( & remote_chain. latest_certificate ( ) . hash ) ;
666+ expected . reverse ( ) ;
667+ assert_eq ! ( expected , storer . stored_certificates ( ) ) ;
614668 }
615669 }
616670}
0 commit comments