@@ -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,34 @@ impl Worker {
707
726
}
708
727
Step :: Commit => {
709
728
cinfo ! ( ENGINE , "move_to_step: Commit." ) ;
729
+ let ( view, block_hash) = state. committed ( ) . expect ( "commit always has committed_view" ) ;
730
+ self . save_last_confirmed_view ( view) ;
731
+
732
+ let proposal_received = self . is_proposal_received ( self . height , view, block_hash) ;
733
+ let proposal_imported = self . client ( ) . block ( & block_hash. into ( ) ) . is_some ( ) ;
734
+ let best_block_header = self . client ( ) . best_block_header ( ) ;
735
+ if best_block_header. number ( ) >= self . height {
736
+ cwarn ! (
737
+ ENGINE ,
738
+ "best_block_header.number() >= self.height ({} >= {}) in Commit state" ,
739
+ best_block_header. number( ) ,
740
+ self . height
741
+ ) ;
742
+ return
743
+ }
744
+
745
+ let should_update_best_block = best_block_header. hash ( ) != block_hash;
746
+
747
+ cdebug ! (
748
+ ENGINE ,
749
+ "commited, proposal_received: {}, proposal_imported: {}, should_update_best_block: {}" ,
750
+ proposal_received,
751
+ proposal_imported,
752
+ should_update_best_block
753
+ ) ;
754
+ if proposal_imported && should_update_best_block {
755
+ self . client ( ) . update_best_as_committed ( block_hash) ;
756
+ }
710
757
}
711
758
}
712
759
}
@@ -818,28 +865,39 @@ impl Worker {
818
865
self . last_two_thirds_majority =
819
866
TwoThirdsMajority :: from_message ( message. on . step . view , message. on . block_hash ) ;
820
867
}
868
+
869
+ if vote_step. step == Step :: Precommit
870
+ && self . height == vote_step. height
871
+ && message. on . block_hash . is_some ( )
872
+ && has_enough_aligned_votes
873
+ {
874
+ if self . can_move_from_commit_to_propose ( ) {
875
+ let height = self . height ;
876
+ self . move_to_height ( height + 1 ) ;
877
+ self . move_to_step ( TendermintState :: Propose , is_restoring) ;
878
+ return
879
+ }
880
+
881
+ let block_hash = message. on . block_hash . expect ( "Upper if already checked block hash" ) ;
882
+ if !self . step . is_commit ( ) {
883
+ self . move_to_step (
884
+ TendermintState :: Commit {
885
+ block_hash,
886
+ view : vote_step. view ,
887
+ } ,
888
+ is_restoring,
889
+ ) ;
890
+ return
891
+ }
892
+ }
893
+
821
894
// Check if it can affect the step transition.
822
895
if self . is_step ( message) {
823
896
let next_step = match self . step {
824
897
TendermintState :: Precommit if message. on . block_hash . is_none ( ) && has_enough_aligned_votes => {
825
898
self . increment_view ( 1 ) ;
826
899
Some ( TendermintState :: Propose )
827
900
}
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
901
// Avoid counting votes twice.
844
902
TendermintState :: Prevote if lock_change => Some ( TendermintState :: Precommit ) ,
845
903
TendermintState :: Prevote if has_enough_aligned_votes => Some ( TendermintState :: Precommit ) ,
@@ -850,14 +908,6 @@ impl Worker {
850
908
self . move_to_step ( step, is_restoring) ;
851
909
return
852
910
}
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
911
}
862
912
863
913
// self.move_to_step() calls self.broadcast_state()
@@ -1227,18 +1277,27 @@ impl Worker {
1227
1277
cinfo ! ( ENGINE , "Precommit timeout without enough votes." ) ;
1228
1278
TendermintState :: Precommit
1229
1279
}
1230
- TendermintState :: Commit => {
1280
+ TendermintState :: Commit {
1281
+ block_hash,
1282
+ view,
1283
+ } => {
1231
1284
cinfo ! ( ENGINE , "Commit timeout." ) ;
1232
- if ! self . check_current_block_exists ( ) {
1285
+ if self . client ( ) . block ( & block_hash . into ( ) ) . is_none ( ) {
1233
1286
cwarn ! ( ENGINE , "Best chain is not updated yet, wait until imported" ) ;
1234
- self . step = TendermintState :: CommitTimedout ;
1287
+ self . step = TendermintState :: CommitTimedout {
1288
+ block_hash,
1289
+ view,
1290
+ } ;
1235
1291
return
1236
1292
}
1293
+
1237
1294
let height = self . height ;
1238
1295
self . move_to_height ( height + 1 ) ;
1239
1296
TendermintState :: Propose
1240
1297
}
1241
- TendermintState :: CommitTimedout => unreachable ! ( ) ,
1298
+ TendermintState :: CommitTimedout {
1299
+ ..
1300
+ } => unreachable ! ( ) ,
1242
1301
} ;
1243
1302
1244
1303
self . move_to_step ( next_step, false ) ;
@@ -1439,6 +1498,24 @@ impl Worker {
1439
1498
}
1440
1499
} ;
1441
1500
1501
+ if self . step . is_commit ( ) && ( imported. len ( ) + enacted. len ( ) == 1 ) {
1502
+ let ( _, committed_block_hash) = self . step . committed ( ) . expect ( "Commit state always has block_hash" ) ;
1503
+ if imported. first ( ) == Some ( & committed_block_hash) {
1504
+ cdebug ! ( ENGINE , "Committed block {} is committed_block_hash" , committed_block_hash) ;
1505
+ self . client ( ) . update_best_as_committed ( committed_block_hash) ;
1506
+ return
1507
+ }
1508
+ if enacted. first ( ) == Some ( & committed_block_hash) {
1509
+ cdebug ! ( ENGINE , "Committed block {} is now the best block" , committed_block_hash) ;
1510
+ if self . can_move_from_commit_to_propose ( ) {
1511
+ let new_height = self . height + 1 ;
1512
+ self . move_to_height ( new_height) ;
1513
+ self . move_to_step ( TendermintState :: Propose , false ) ;
1514
+ return
1515
+ }
1516
+ }
1517
+ }
1518
+
1442
1519
if !imported. is_empty ( ) {
1443
1520
let mut height_changed = false ;
1444
1521
for hash in imported {
@@ -1463,11 +1540,6 @@ impl Worker {
1463
1540
return
1464
1541
}
1465
1542
}
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
1543
}
1472
1544
1473
1545
fn send_proposal_block (
0 commit comments