github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/orderer/sbft/simplebft/xset.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 "reflect" 20 21 // makeXset returns a request subject that should be proposed as batches 22 // for new-view. If there is no request to select (null request), it 23 // will return nil for subject. makeXset always returns a batches for 24 // the most recent checkpoint. 25 func (s *SBFT) makeXset(vcs []*ViewChange) (*Subject, *Batch, bool) { 26 // first select base commit (equivalent to checkpoint/low water mark) 27 var best *Batch 28 for _, vc := range vcs { 29 seq := vc.Checkpoint.DecodeHeader().Seq 30 if best == nil || seq > best.DecodeHeader().Seq { 31 best = vc.Checkpoint 32 } 33 } 34 35 if best == nil { 36 return nil, nil, false 37 } 38 39 next := best.DecodeHeader().Seq + 1 40 log.Debugf("replica %d: xset starts at commit %d", s.id, next) 41 42 // now determine which request could have executed for best+1 43 var xset *Subject 44 45 // This is according to Castro's TOCS PBFT, Fig. 4 46 // find some message m in S, 47 emptycount := 0 48 nextm: 49 for _, m := range vcs { 50 notfound := true 51 // which has <n,d,v> in its Pset 52 for _, mtuple := range m.Pset { 53 log.Debugf("replica %d: trying %v", s.id, mtuple) 54 if mtuple.Seq.Seq < next { 55 continue 56 } 57 58 // we found an entry for next 59 notfound = false 60 61 // A1. where 2f+1 messages mp from S 62 count := 0 63 nextmp: 64 for _, mp := range vcs { 65 // "low watermark" is less than n 66 if mp.Checkpoint.DecodeHeader().Seq > mtuple.Seq.Seq { 67 continue 68 } 69 // and all <n,d',v'> in its Pset 70 for _, mptuple := range mp.Pset { 71 log.Debugf("replica %d: matching %v", s.id, mptuple) 72 if mptuple.Seq.Seq != mtuple.Seq.Seq { 73 continue 74 } 75 76 // either v' < v or (v' == v and d' == d) 77 if mptuple.Seq.View < mtuple.Seq.View || 78 (mptuple.Seq.View == mtuple.Seq.View && reflect.DeepEqual(mptuple.Digest, mtuple.Digest)) { 79 continue 80 } else { 81 continue nextmp 82 } 83 } 84 count += 1 85 } 86 if count < s.viewChangeQuorum() { 87 continue 88 } 89 log.Debugf("replica %d: found %d replicas for Pset %d/%d", s.id, count, mtuple.Seq.Seq, mtuple.Seq.View) 90 91 // A2. f+1 messages mp from S 92 count = 0 93 for _, mp := range vcs { 94 // and all <n,d',v'> in its Qset 95 for _, mptuple := range mp.Qset { 96 if mptuple.Seq.Seq != mtuple.Seq.Seq { 97 continue 98 } 99 if mptuple.Seq.View < mtuple.Seq.View { 100 continue 101 } 102 // d' == d 103 if !reflect.DeepEqual(mptuple.Digest, mtuple.Digest) { 104 continue 105 } 106 count += 1 107 // there exists one ... 108 break 109 } 110 } 111 if count < s.oneCorrectQuorum() { 112 continue 113 } 114 log.Debugf("replica %d: found %d replicas for Qset %d", s.id, count, mtuple.Seq.Seq) 115 116 log.Debugf("replica %d: selecting %d with %x", s.id, next, mtuple.Digest) 117 xset = &Subject{ 118 Seq: &SeqView{Seq: next, View: s.view}, 119 Digest: mtuple.Digest, 120 } 121 break nextm 122 } 123 124 if notfound { 125 emptycount += 1 126 } 127 } 128 129 // B. otherwise select null request 130 // We actually don't select a null request, but report the most recent batches instead. 131 if emptycount >= s.viewChangeQuorum() { 132 log.Debugf("replica %d: no pertinent requests found for %d", s.id, next) 133 return nil, best, true 134 } 135 136 if xset == nil { 137 return nil, nil, false 138 } 139 140 return xset, best, true 141 }