github.com/leonlxy/hyperledger@v1.0.0-alpha.0.20170427033203-34922035d248/orderer/sbft/simplebft/newview.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 (
    20  	"bytes"
    21  	"fmt"
    22  	"reflect"
    23  )
    24  
    25  func (s *SBFT) maybeSendNewView() {
    26  	if s.lastNewViewSent != nil && s.lastNewViewSent.View == s.view {
    27  		return
    28  	}
    29  
    30  	vset := make(map[uint64]*Signed)
    31  	var vcs []*ViewChange
    32  
    33  	for src, state := range s.replicaState {
    34  		if state.viewchange != nil && state.viewchange.View == s.view {
    35  			vset[uint64(src)] = state.signedViewchange
    36  			vcs = append(vcs, state.viewchange)
    37  		}
    38  	}
    39  
    40  	xset, _, ok := s.makeXset(vcs)
    41  	if !ok {
    42  		log.Debugf("replica %d: xset not yet sufficient", s.id)
    43  		return
    44  	}
    45  
    46  	var batch *Batch
    47  	if xset == nil {
    48  		// no need for batches, it is contained in the vset
    49  	} else if reflect.DeepEqual(s.cur.subject.Digest, xset.Digest) {
    50  		batch = s.cur.preprep.Batch
    51  	} else {
    52  		log.Warningf("replica %d: forfeiting primary - do not have request in store for %d %x", s.id, xset.Seq.Seq, xset.Digest)
    53  		xset = nil
    54  	}
    55  
    56  	nv := &NewView{
    57  		View:  s.view,
    58  		Vset:  vset,
    59  		Xset:  xset,
    60  		Batch: batch,
    61  	}
    62  
    63  	log.Noticef("replica %d: sending new view for %d", s.id, nv.View)
    64  	s.lastNewViewSent = nv
    65  	s.broadcast(&Msg{&Msg_NewView{nv}})
    66  }
    67  
    68  func (s *SBFT) checkNewViewSignatures(nv *NewView) ([]*ViewChange, error) {
    69  	var vcs []*ViewChange
    70  	for vcsrc, svc := range nv.Vset {
    71  		vc := &ViewChange{}
    72  		err := s.checkSig(svc, vcsrc, vc)
    73  		if err == nil {
    74  			_, err = s.checkBatch(vc.Checkpoint, false, true)
    75  			if vc.View != nv.View {
    76  				err = fmt.Errorf("view does not match")
    77  			}
    78  		}
    79  		if err != nil {
    80  			return nil, fmt.Errorf("viewchange from %d: %s", vcsrc, err)
    81  		}
    82  		vcs = append(vcs, vc)
    83  	}
    84  
    85  	return vcs, nil
    86  }
    87  
    88  func (s *SBFT) handleNewView(nv *NewView, src uint64) {
    89  	if nv == nil {
    90  		return
    91  	}
    92  
    93  	if nv.View < s.view {
    94  		log.Debugf("replica %d: discarding old new view from %d for %d, we are in %d", s.id, src, nv.View, s.view)
    95  		return
    96  	}
    97  
    98  	if nv.View == s.view && s.activeView {
    99  		log.Debugf("replica %d: discarding new view from %d for %d, we are already active in %d", s.id, src, nv.View, s.view)
   100  		return
   101  	}
   102  
   103  	if src != s.primaryIDView(nv.View) {
   104  		log.Warningf("replica %d: invalid new view from %d for %d", s.id, src, nv.View)
   105  		return
   106  	}
   107  
   108  	vcs, err := s.checkNewViewSignatures(nv)
   109  	if err != nil {
   110  		log.Warningf("replica %d: invalid new view from %d: %s", s.id, src, err)
   111  		s.sendViewChange()
   112  		return
   113  	}
   114  
   115  	xset, prevBatch, ok := s.makeXset(vcs)
   116  
   117  	if !ok || !reflect.DeepEqual(nv.Xset, xset) {
   118  		log.Warningf("replica %d: invalid new view from %d: xset incorrect: %v, %v", s.id, src, nv.Xset, xset)
   119  		s.sendViewChange()
   120  		return
   121  	}
   122  
   123  	if nv.Xset == nil {
   124  		if nv.Batch != nil {
   125  			log.Warningf("replica %d: invalid new view from %d: null request should come with null batches", s.id, src)
   126  			s.sendViewChange()
   127  			return
   128  		}
   129  	} else if nv.Batch == nil || !bytes.Equal(nv.Batch.Hash(), nv.Xset.Digest) {
   130  		log.Warningf("replica %d: invalid new view from %d: batches head hash does not match xset: %x, %x, %v",
   131  			s.id, src, hash(nv.Batch.Header), nv.Xset.Digest, nv)
   132  		s.sendViewChange()
   133  		return
   134  	}
   135  
   136  	if nv.Batch != nil {
   137  		_, err = s.checkBatch(nv.Batch, true, false)
   138  		if err != nil {
   139  			log.Warningf("replica %d: invalid new view from %d: invalid batches, %s",
   140  				s.id, src, err)
   141  			s.sendViewChange()
   142  			return
   143  		}
   144  	}
   145  
   146  	s.view = nv.View
   147  	s.discardBacklog(s.primaryID())
   148  
   149  	// maybe deliver previous batches
   150  	if s.sys.LastBatch(s.chainId).DecodeHeader().Seq < prevBatch.DecodeHeader().Seq {
   151  		if prevBatch.DecodeHeader().Seq == s.cur.subject.Seq.Seq {
   152  			// we just received a signature set for a request which we preprepared, but never delivered.
   153  			// check first if the locally preprepared request matches the signature set
   154  			if !reflect.DeepEqual(prevBatch.DecodeHeader().DataHash, s.cur.preprep.Batch.DecodeHeader().DataHash) {
   155  				log.Warningf("replica %d: [seq %d] request checkpointed in a previous view does not match locally preprepared one, delivering batches without payload", s.id, s.cur.subject.Seq.Seq)
   156  			} else {
   157  				log.Debugf("replica %d: [seq %d] request checkpointed in a previous view with matching preprepare, completing and delivering the batches with payload", s.id, s.cur.subject.Seq.Seq)
   158  				prevBatch.Payloads = s.cur.preprep.Batch.Payloads
   159  			}
   160  		}
   161  		// TODO we should not do this here, as prevBatch was already delivered
   162  		blockOK, committers := s.getCommittersFromBatch(prevBatch)
   163  		if !blockOK {
   164  			log.Panic("Replica %d: our last checkpointed batch is erroneous (block cutter).", s.id)
   165  		}
   166  		// TODO what should we do with the remaining?
   167  		s.deliverBatch(prevBatch, committers)
   168  	}
   169  
   170  	// after a new-view message, prepare to accept new requests.
   171  	s.activeView = true
   172  	s.cur.checkpointDone = true
   173  	s.cur.subject.Seq.Seq = 0
   174  
   175  	log.Infof("replica %d now active in view %d; primary: %v", s.id, s.view, s.isPrimary())
   176  
   177  	//process pre-prepare if piggybacked to new-view
   178  	if nv.Batch != nil {
   179  		pp := &Preprepare{
   180  			Seq:   &SeqView{Seq: nv.Batch.DecodeHeader().Seq, View: s.view},
   181  			Batch: nv.Batch,
   182  		}
   183  		blockOK, committers := s.getCommittersFromBatch(nv.Batch)
   184  		if !blockOK {
   185  			log.Debugf("Replica %d: new view %d batch erroneous (block cutter).", s.id, nv.View)
   186  			s.sendViewChange()
   187  		}
   188  
   189  		s.handleCheckedPreprepare(pp, committers)
   190  	} else {
   191  		s.cancelViewChangeTimer()
   192  		s.maybeSendNextBatch()
   193  	}
   194  
   195  	s.processBacklog()
   196  }