github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/orderer/sbft/simplebft/checkpoint.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  	"fmt"
    21  	"reflect"
    22  )
    23  
    24  func (s *SBFT) makeCheckpoint() *Checkpoint {
    25  	sig := s.sys.Sign(s.cur.subject.Digest)
    26  	c := &Checkpoint{
    27  		Seq:       s.cur.subject.Seq.Seq,
    28  		Digest:    s.cur.subject.Digest,
    29  		Signature: sig,
    30  	}
    31  	return c
    32  }
    33  
    34  func (s *SBFT) sendCheckpoint() {
    35  	s.broadcast(&Msg{&Msg_Checkpoint{s.makeCheckpoint()}})
    36  }
    37  
    38  func (s *SBFT) handleCheckpoint(c *Checkpoint, src uint64) {
    39  	if s.cur.checkpointDone {
    40  		return
    41  	}
    42  
    43  	if c.Seq < s.cur.subject.Seq.Seq {
    44  		// old message
    45  		return
    46  	}
    47  
    48  	err := s.checkBytesSig(c.Digest, src, c.Signature)
    49  	if err != nil {
    50  		log.Infof("replica %d: checkpoint signature invalid for %d from %d", s.id, c.Seq, src)
    51  		return
    52  	}
    53  
    54  	// TODO should we always accept checkpoints?
    55  	if c.Seq != s.cur.subject.Seq.Seq {
    56  		log.Infof("replica %d: checkpoint does not match expected subject %v, got %v", s.id, &s.cur.subject, c)
    57  		return
    58  	}
    59  	if _, ok := s.cur.checkpoint[src]; ok {
    60  		log.Infof("replica %d: duplicate checkpoint for %d from %d", s.id, c.Seq, src)
    61  	}
    62  	s.cur.checkpoint[src] = c
    63  
    64  	max := "_"
    65  	sums := make(map[string][]uint64)
    66  	for csrc, c := range s.cur.checkpoint {
    67  		sum := fmt.Sprintf("%x", c.Digest)
    68  		sums[sum] = append(sums[sum], csrc)
    69  
    70  		if len(sums[sum]) >= s.oneCorrectQuorum() {
    71  			max = sum
    72  		}
    73  	}
    74  
    75  	replicas, ok := sums[max]
    76  	if !ok {
    77  		return
    78  	}
    79  
    80  	// got a weak checkpoint
    81  
    82  	cpset := make(map[uint64][]byte)
    83  	for _, r := range replicas {
    84  		cp := s.cur.checkpoint[r]
    85  		cpset[r] = cp.Signature
    86  	}
    87  
    88  	c = s.cur.checkpoint[replicas[0]]
    89  
    90  	if !reflect.DeepEqual(c.Digest, s.cur.subject.Digest) {
    91  		log.Warningf("replica %d: weak checkpoint %x does not match our state %x --- primary %d of view %d is probably Byzantine, sending view change",
    92  			s.id, c.Digest, s.cur.subject.Digest, s.primaryID(), s.view)
    93  		s.sendViewChange()
    94  		return
    95  	}
    96  
    97  	// ignore null requests
    98  	batch := *s.cur.preprep.Batch
    99  	batch.Signatures = cpset
   100  	s.deliverBatch(&batch, s.cur.committers)
   101  	log.Infof("replica %d: request %s %s delivered on %d (completed common case)", s.id, s.cur.subject.Seq, hash2str(s.cur.subject.Digest), s.id)
   102  	s.maybeSendNextBatch()
   103  	s.processBacklog()
   104  }