@@ -405,6 +405,10 @@ impl Worker {
405
405
406
406
/// Check Tendermint can move from the commit step to the propose step
407
407
fn can_move_from_commit_to_propose ( & self ) -> bool {
408
+ if !self . step . is_commit ( ) {
409
+ return false
410
+ }
411
+
408
412
let vote_step = VoteStep :: new ( self . height , self . last_confirmed_view , Step :: Precommit ) ;
409
413
if self . step . is_commit_timedout ( ) && self . check_current_block_exists ( ) {
410
414
cinfo ! ( ENGINE , "Transition to Propose because best block is changed after commit timeout" ) ;
@@ -442,6 +446,20 @@ impl Worker {
442
446
Some ( ( proposal. signature , proposal. signer_index , bytes) )
443
447
}
444
448
449
+ fn is_proposal_received ( & self , height : Height , view : View , block_hash : BlockHash ) -> bool {
450
+ let all_votes = self . votes . get_all_votes_in_round ( & VoteStep {
451
+ height,
452
+ view,
453
+ step : Step :: Propose ,
454
+ } ) ;
455
+
456
+ if let Some ( proposal) = all_votes. first ( ) {
457
+ proposal. on . block_hash . expect ( "Proposal message always include block hash" ) == block_hash
458
+ } else {
459
+ false
460
+ }
461
+ }
462
+
445
463
pub fn vote_step ( & self ) -> VoteStep {
446
464
VoteStep {
447
465
height : self . height ,
@@ -592,6 +610,7 @@ impl Worker {
592
610
self . votes_received = BitSet :: new ( ) ;
593
611
}
594
612
613
+ #[ allow( clippy:: cognitive_complexity) ]
595
614
fn move_to_step ( & mut self , state : TendermintState , is_restoring : bool ) {
596
615
ctrace ! ( ENGINE , "Transition to {:?} triggered." , state) ;
597
616
let prev_step = mem:: replace ( & mut self . step , state. clone ( ) ) ;
@@ -707,6 +726,47 @@ impl Worker {
707
726
}
708
727
Step :: Commit => {
709
728
cinfo ! ( ENGINE , "move_to_step: Commit." ) ;
729
+ let view = state. committed_view ( ) . expect ( "commit always has committed_view" ) ;
730
+ let block_hash = state. committed_block_hash ( ) . expect ( "commit always has committed_block_hash" ) ;
731
+ self . save_last_confirmed_view ( view) ;
732
+
733
+ let proposal_received = self . is_proposal_received ( self . height , view, block_hash) ;
734
+ let proposal_imported = self . client ( ) . block ( & block_hash. into ( ) ) . is_some ( ) ;
735
+ let best_block_header = self . client ( ) . best_block_header ( ) ;
736
+ if best_block_header. number ( ) > self . height {
737
+ cwarn ! (
738
+ ENGINE ,
739
+ "Best block's number {} is larger than tendermint height {} in Commit state" ,
740
+ best_block_header. number( ) ,
741
+ self . height
742
+ ) ;
743
+ return
744
+ } else if best_block_header. number ( ) == self . height {
745
+ cwarn ! (
746
+ ENGINE ,
747
+ "Best block's number {} is the same as the tendermint height {} in Commit state" ,
748
+ best_block_header. number( ) ,
749
+ self . height
750
+ ) ;
751
+ return
752
+ }
753
+ let best_block_changed = best_block_header. hash ( ) == block_hash;
754
+
755
+ match ( proposal_received, proposal_imported, best_block_changed) {
756
+ ( false , false , _) => {
757
+ cdebug ! ( ENGINE , "committed but proposal({}) is not received wait the proposal" , block_hash) ;
758
+ }
759
+ ( true , false , _) => {
760
+ cdebug ! ( ENGINE , "committed but proposal({}) is not imported wait the proposal" , block_hash) ;
761
+ }
762
+ ( _, true , false ) => {
763
+ cdebug ! ( ENGINE , "committed but proposal({}) is imported update the best block" , block_hash) ;
764
+ self . client ( ) . update_best_as_committed ( block_hash) ;
765
+ }
766
+ ( _, true , true ) => {
767
+ cdebug ! ( ENGINE , "committed proposal({}) is imported and best is changed" , block_hash) ;
768
+ }
769
+ }
710
770
}
711
771
}
712
772
}
@@ -818,28 +878,39 @@ impl Worker {
818
878
self . last_two_thirds_majority =
819
879
TwoThirdsMajority :: from_message ( message. on . step . view , message. on . block_hash ) ;
820
880
}
881
+
882
+ if vote_step. step == Step :: Precommit
883
+ && self . height == vote_step. height
884
+ && message. on . block_hash . is_some ( )
885
+ && has_enough_aligned_votes
886
+ {
887
+ if self . can_move_from_commit_to_propose ( ) {
888
+ let height = self . height ;
889
+ self . move_to_height ( height + 1 ) ;
890
+ self . move_to_step ( TendermintState :: Propose , is_restoring) ;
891
+ return
892
+ }
893
+
894
+ let block_hash = message. on . block_hash . expect ( "Upper if already checked block hash" ) ;
895
+ if !self . step . is_commit ( ) {
896
+ self . move_to_step (
897
+ TendermintState :: Commit {
898
+ block_hash,
899
+ view : vote_step. view ,
900
+ } ,
901
+ is_restoring,
902
+ ) ;
903
+ return
904
+ }
905
+ }
906
+
821
907
// Check if it can affect the step transition.
822
908
if self . is_step ( message) {
823
909
let next_step = match self . step {
824
910
TendermintState :: Precommit if message. on . block_hash . is_none ( ) && has_enough_aligned_votes => {
825
911
self . increment_view ( 1 ) ;
826
912
Some ( TendermintState :: Propose )
827
913
}
828
- TendermintState :: Precommit if has_enough_aligned_votes => {
829
- let bh = message. on . block_hash . expect ( "previous guard ensures is_some; qed" ) ;
830
- if self . client ( ) . block ( & BlockId :: Hash ( bh) ) . is_some ( ) {
831
- // Commit the block, and update the last confirmed view
832
- self . save_last_confirmed_view ( message. on . step . view ) ;
833
-
834
- // Update the best block hash as the hash of the committed block
835
- self . client ( ) . update_best_as_committed ( bh) ;
836
- Some ( TendermintState :: Commit )
837
- } else {
838
- cwarn ! ( ENGINE , "Cannot find a proposal which committed" ) ;
839
- self . increment_view ( 1 ) ;
840
- Some ( TendermintState :: Propose )
841
- }
842
- }
843
914
// Avoid counting votes twice.
844
915
TendermintState :: Prevote if lock_change => Some ( TendermintState :: Precommit ) ,
845
916
TendermintState :: Prevote if has_enough_aligned_votes => Some ( TendermintState :: Precommit ) ,
@@ -850,14 +921,6 @@ impl Worker {
850
921
self . move_to_step ( step, is_restoring) ;
851
922
return
852
923
}
853
- } else if vote_step. step == Step :: Precommit
854
- && self . height == vote_step. height
855
- && self . can_move_from_commit_to_propose ( )
856
- {
857
- let height = self . height ;
858
- self . move_to_height ( height + 1 ) ;
859
- self . move_to_step ( TendermintState :: Propose , is_restoring) ;
860
- return
861
924
}
862
925
863
926
// self.move_to_step() calls self.broadcast_state()
@@ -1227,18 +1290,27 @@ impl Worker {
1227
1290
cinfo ! ( ENGINE , "Precommit timeout without enough votes." ) ;
1228
1291
TendermintState :: Precommit
1229
1292
}
1230
- TendermintState :: Commit => {
1293
+ TendermintState :: Commit {
1294
+ block_hash,
1295
+ view,
1296
+ } => {
1231
1297
cinfo ! ( ENGINE , "Commit timeout." ) ;
1232
- if ! self . check_current_block_exists ( ) {
1298
+ if self . client ( ) . block ( & block_hash . into ( ) ) . is_none ( ) {
1233
1299
cwarn ! ( ENGINE , "Best chain is not updated yet, wait until imported" ) ;
1234
- self . step = TendermintState :: CommitTimedout ;
1300
+ self . step = TendermintState :: CommitTimedout {
1301
+ block_hash,
1302
+ view,
1303
+ } ;
1235
1304
return
1236
1305
}
1306
+
1237
1307
let height = self . height ;
1238
1308
self . move_to_height ( height + 1 ) ;
1239
1309
TendermintState :: Propose
1240
1310
}
1241
- TendermintState :: CommitTimedout => unreachable ! ( ) ,
1311
+ TendermintState :: CommitTimedout {
1312
+ ..
1313
+ } => unreachable ! ( ) ,
1242
1314
} ;
1243
1315
1244
1316
self . move_to_step ( next_step, false ) ;
@@ -1439,6 +1511,24 @@ impl Worker {
1439
1511
}
1440
1512
} ;
1441
1513
1514
+ if self . step . is_commit ( ) && ( imported. len ( ) + enacted. len ( ) == 1 ) {
1515
+ let committed_block_hash = self . step . committed_block_hash ( ) . expect ( "Commit state always has block_hash" ) ;
1516
+ if imported. first ( ) == Some ( & committed_block_hash) {
1517
+ cdebug ! ( ENGINE , "Committed block {} is committed_block_hash" , committed_block_hash) ;
1518
+ self . client ( ) . update_best_as_committed ( committed_block_hash) ;
1519
+ return
1520
+ }
1521
+ if enacted. first ( ) == Some ( & committed_block_hash) {
1522
+ cdebug ! ( ENGINE , "Committed block {} is now the best block" , committed_block_hash) ;
1523
+ if self . can_move_from_commit_to_propose ( ) {
1524
+ let new_height = self . height + 1 ;
1525
+ self . move_to_height ( new_height) ;
1526
+ self . move_to_step ( TendermintState :: Propose , false ) ;
1527
+ return
1528
+ }
1529
+ }
1530
+ }
1531
+
1442
1532
if !imported. is_empty ( ) {
1443
1533
let mut height_changed = false ;
1444
1534
for hash in imported {
@@ -1463,11 +1553,6 @@ impl Worker {
1463
1553
return
1464
1554
}
1465
1555
}
1466
- if !enacted. is_empty ( ) && self . can_move_from_commit_to_propose ( ) {
1467
- let new_height = self . height + 1 ;
1468
- self . move_to_height ( new_height) ;
1469
- self . move_to_step ( TendermintState :: Propose , false )
1470
- }
1471
1556
}
1472
1557
1473
1558
fn send_proposal_block (
0 commit comments