github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/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  }