@@ -766,8 +766,89 @@ impl<T: RawRepository> DistributedRepository<T> {
766
766
/// Creates an extra-agenda transaction commit on top of the `work` branch.
767
767
pub async fn create_extra_agenda_transaction (
768
768
& mut self ,
769
- _transaction : & ExtraAgendaTransaction ,
769
+ transaction : & ExtraAgendaTransaction ,
770
770
) -> Result < CommitHash , Error > {
771
- unimplemented ! ( )
771
+ let work_commit = self . raw . locate_branch ( WORK_BRANCH_NAME . into ( ) ) . await ?;
772
+ let last_header_commit = self . raw . locate_branch ( FINALIZED_BRANCH_NAME . into ( ) ) . await ?;
773
+ let reserved_state = self . get_reserved_state ( ) . await ?;
774
+
775
+ // Check if the `work` branch is rebased on top of the `finalized` branch.
776
+ if self
777
+ . raw
778
+ . find_merge_base ( last_header_commit, work_commit)
779
+ . await ?
780
+ != last_header_commit
781
+ {
782
+ return Err ( eyre ! (
783
+ "branch {} should be rebased on {}" ,
784
+ WORK_BRANCH_NAME ,
785
+ FINALIZED_BRANCH_NAME
786
+ ) ) ;
787
+ }
788
+
789
+ // Construct a commit list starting from the next commit of the last finalized block to the `branch_commit`(the most recent commit of the branch)
790
+ let ancestor_commits = self . raw . list_ancestors ( work_commit, Some ( 256 ) ) . await ?;
791
+ let position = ancestor_commits
792
+ . iter ( )
793
+ . position ( |c| * c == last_header_commit)
794
+ . expect ( "TODO: handle the case where it exceeds the limit." ) ;
795
+ let commits = stream:: iter ( ancestor_commits. iter ( ) . take ( position) . rev ( ) . cloned ( ) . map (
796
+ |c| {
797
+ let raw = & self . raw ;
798
+ async move { raw. read_semantic_commit ( c) . await . map ( |x| ( x, c) ) }
799
+ } ,
800
+ ) )
801
+ . buffered ( 256 )
802
+ . collect :: < Vec < _ > > ( )
803
+ . await ;
804
+ let mut commits = commits. into_iter ( ) . collect :: < Result < Vec < _ > , _ > > ( ) ?;
805
+ // Add most recent commit of the branch to the list since it is not included in the ancestor commits
806
+ commits. push ( (
807
+ self . raw . read_semantic_commit ( work_commit) . await ?,
808
+ work_commit,
809
+ ) ) ;
810
+ let commits = commits
811
+ . into_iter ( )
812
+ . map ( |( commit, hash) | {
813
+ from_semantic_commit ( commit, reserved_state. clone ( ) )
814
+ . map_err ( |e| ( e, hash) )
815
+ . map ( |x| ( x, hash) )
816
+ } )
817
+ . collect :: < Result < Vec < _ > , _ > > ( )
818
+ . map_err ( |( error, hash) | eyre ! ( "failed to convert the commit {}: {}" , hash, error) ) ?;
819
+
820
+ // Check the validity of the commit sequence
821
+ let last_header = self . get_last_finalized_block_header ( ) . await ?;
822
+ let mut verifier = CommitSequenceVerifier :: new ( last_header. clone ( ) , reserved_state. clone ( ) )
823
+ . map_err ( |e| eyre ! ( "verification error on commit {}: {}" , last_header_commit, e) ) ?;
824
+ for ( commit, hash) in commits. iter ( ) {
825
+ verifier
826
+ . apply_commit ( commit)
827
+ . map_err ( |e| eyre ! ( "verification error on commit {}: {}" , hash, e) ) ?;
828
+ }
829
+
830
+ // Check whether the commit sequence is in agenda proof phase or extra-agenda transaction phase
831
+ let ( last_commit, _) = commits
832
+ . last ( )
833
+ . ok_or_else ( || eyre ! ( "work branch does not contain any commit" ) ) ?;
834
+ match last_commit {
835
+ Commit :: AgendaProof ( _) => { }
836
+ Commit :: ExtraAgendaTransaction ( _) => { }
837
+ x => {
838
+ return Err ( eyre ! (
839
+ "an extra-agenda transaction commit cannot be created on top of a commit of type {:?}" ,
840
+ x
841
+ ) )
842
+ }
843
+ }
844
+
845
+ let extra_agenda_tx_commit = Commit :: ExtraAgendaTransaction ( transaction. clone ( ) ) ;
846
+
847
+ let semantic_commit = to_semantic_commit ( & extra_agenda_tx_commit, reserved_state) ?;
848
+
849
+ self . raw . checkout_clean ( ) . await ?;
850
+ self . raw . checkout ( WORK_BRANCH_NAME . into ( ) ) . await ?;
851
+ let result = self . raw . create_semantic_commit ( semantic_commit) . await ?;
852
+ Ok ( result)
772
853
}
773
854
}
0 commit comments