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 }