github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/orderer/sbft/simplebft/viewchange.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package simplebft 18 19 import "time" 20 21 func (s *SBFT) sendViewChange() { 22 s.view = s.nextView() 23 s.cur.timeout.Cancel() 24 s.activeView = false 25 for src := range s.replicaState { 26 state := &s.replicaState[src] 27 if state.viewchange != nil && state.viewchange.View < s.view { 28 state.viewchange = nil 29 } 30 } 31 log.Noticef("replica %d: sending viewchange for view %d", s.id, s.view) 32 33 var q, p []*Subject 34 if s.cur.prepared { 35 p = append(p, &s.cur.subject) 36 } 37 if s.cur.preprep != nil { 38 q = append(q, &s.cur.subject) 39 } 40 41 // TODO fix batches synchronization as we send no payload here 42 checkpoint := *s.sys.LastBatch(s.chainId) 43 checkpoint.Payloads = nil // don't send the big payload 44 45 vc := &ViewChange{ 46 View: s.view, 47 Qset: q, 48 Pset: p, 49 Checkpoint: &checkpoint, 50 } 51 svc := s.sign(vc) 52 s.viewChangeTimer.Cancel() 53 s.cur.timeout.Cancel() 54 55 s.sys.Persist(s.chainId, viewchange, svc) 56 s.broadcast(&Msg{&Msg_ViewChange{svc}}) 57 } 58 59 func (s *SBFT) cancelViewChangeTimer() { 60 s.viewChangeTimer.Cancel() 61 s.viewChangeTimeout = time.Duration(s.config.RequestTimeoutNsec) * 2 62 } 63 64 func (s *SBFT) handleViewChange(svc *Signed, src uint64) { 65 vc := &ViewChange{} 66 err := s.checkSig(svc, src, vc) 67 if err == nil { 68 _, err = s.checkBatch(vc.Checkpoint, false, true) 69 } 70 if err != nil { 71 log.Noticef("replica %d: invalid viewchange: %s", s.id, err) 72 return 73 } 74 if vc.View < s.view { 75 log.Debugf("replica %d: old view change from %d for view %d, we are in view %d", s.id, src, vc.View, s.view) 76 return 77 } 78 if ovc := s.replicaState[src].viewchange; ovc != nil && vc.View <= ovc.View { 79 log.Noticef("replica %d: duplicate view change for %d from %d", s.id, vc.View, src) 80 return 81 } 82 83 log.Infof("replica %d: viewchange from %d: %v", s.id, src, vc) 84 s.replicaState[src].viewchange = vc 85 s.replicaState[src].signedViewchange = svc 86 87 min := vc.View 88 89 //amplify current primary abdication 90 if s.view == min-1 && s.primaryID() == src { 91 s.sendViewChange() 92 return 93 } 94 95 quorum := 0 96 for _, state := range s.replicaState { 97 if state.viewchange != nil { 98 quorum++ 99 if state.viewchange.View < min { 100 min = state.viewchange.View 101 } 102 } 103 } 104 105 if quorum == s.oneCorrectQuorum() { 106 // catch up to the minimum view 107 if s.view < min { 108 log.Noticef("replica %d: we are behind on view change, resending for newer view", s.id) 109 s.view = min - 1 110 s.sendViewChange() 111 return 112 } 113 } 114 115 if quorum == s.viewChangeQuorum() { 116 log.Noticef("replica %d: received view change quorum, starting view change timer", s.id) 117 s.viewChangeTimer = s.sys.Timer(s.viewChangeTimeout, func() { 118 s.viewChangeTimeout *= 2 119 log.Noticef("replica %d: view change timed out, sending next", s.id) 120 s.sendViewChange() 121 }) 122 } 123 124 if s.isPrimary() { 125 s.maybeSendNewView() 126 } 127 }